В Perl там недостатки к генерации методов считывания и методов set, а не жесткого кодирования их?

При использовании Python 3 Вы можете Вы использовать звезду, прежде чем переменная (на левой стороне присвоения), чтобы иметь его будет списком в распаковке.

# Example 1: a is 1 and b is [2, 3]

a, *b = [1, 2, 3]

# Example 2: a is 1, b is [2, 3], and c is 4

a, *b, c = [1, 2, 3, 4]

# Example 3: b is [1, 2] and c is 3

*b, c = [1, 2, 3]       

# Example 4: a is 1 and b is []

a, *b = [1]
7
задан FMc 7 September 2009 в 16:58
поделиться

7 ответов

Не должно быть разницы в производительности во время выполнения , если результирующий код будет одинаковым в обоих случаях . Однако обычно это невозможно, если вы не используете строку eval для создания ваших подпрограмм. Например, предоставленный вами код:

... = sub { $_[0]->{$a} };

будет немного медленнее, чем код, который вы написали бы вручную:

sub foo { $_[0]->{'foo'} }

просто потому, что первый должен получить значение переменной $ a, прежде чем использовать ее в качестве ключ к хешу, тогда как последний использует константу в качестве хеш-ключа. Кроме того, в стороне, shift обычно быстрее, чем $ _ [0] . Вот код теста:

use Benchmark qw(cmpthese);

package Foo;

sub manual_shift { shift->{'foo'} }
sub manual_index { $_[0]->{'foo'} }

my $attr = 'foo';

*dynamic_shift = sub { shift->{$attr} };
*dynamic_index = sub { $_[0]->{$attr} };

package main;

my $o = bless { foo => 123 }, 'Foo';

cmpthese(-2, {
  manual_shift  => sub { my $a = $o->manual_shift },
  manual_index  => sub { my $a = $o->manual_index },
  dynamic_shift => sub { my $a = $o->dynamic_shift },
  dynamic_index => sub { my $a = $o->dynamic_index },
});

и результаты в моей системе:

                   Rate dynamic_index  manual_index dynamic_shift  manual_shift
dynamic_index 1799024/s            --           -3%           -4%           -7%
manual_index  1853616/s            3%            --           -1%           -4%
dynamic_shift 1873183/s            4%            1%            --           -3%
manual_shift  1937019/s            8%            4%            3%            --

Они настолько близки, что различия могут затеряться в шуме, но по результатам многих испытаний, я думаю, вы увидите, что вариант с «ручным переключением» - это быстрейший. Но, как и в случае со всеми подобными микробенчмарками, вы должны протестировать свой точный сценарий на вашем оборудовании и вашей версии perl, чтобы быть уверенным в чем-либо.

И вот строка eval, добавленная в смесь.

eval "sub eval_index { \$_[0]->{'$attr'} }";
eval "sub eval_shift { shift->{'$attr'} }";

Она должна быть точно такой же. как «ручные» варианты, плюс-минус статистический шум. Мои результаты:

                   Rate dynamic_index manual_index dynamic_shift manual_shift eval_shift eval_index
dynamic_index 1820444/s            --          -1%           -2%          -3%        -4%        -5%
manual_index  1835005/s            1%           --           -1%          -2%        -3%        -4%
dynamic_shift 1858131/s            2%           1%            --          -1%        -2%        -3%
manual_shift  1876708/s            3%           2%            1%           --        -1%        -2%
eval_shift    1894132/s            4%           3%            2%           1%         --        -1%
eval_index    1914060/s            5%           4%            3%           2%         1%         --

Опять же, все они настолько близки, что вам придется приложить немало усилий и выполнить множество попыток, чтобы отделить сигнал от шума. Но разница между использованием константы в качестве хеш-ключа и использованием переменной (значение которой необходимо сначала получить) в качестве хеш-ключа должна быть очевидна. (Оптимизация shift - это отдельный вопрос и, скорее всего, изменится так или иначе в прошлых или будущих версиях Perl.)

8
ответ дан 6 December 2019 в 06:14
поделиться

Главный недостаток хорошо сгенерированных средств доступа состоит в том, что они не работают с инструментами, полагающимися на статический анализ. Например, автозаполнение метода вашей IDE. Если это часть большого проекта, я настоятельно рекомендую вам взглянуть на Moose . Это правильная генерация аксессуаров (и многое другое). Достаточно популярно, что поддержка добавляется к IDE, так что вышеупомянутая проблема исчезнет в должное время.

На CPAN есть много генераторов доступа, которые просты в использовании и генерируют умеренно эффективный код. Если производительность является проблемой, то - при условии, что вы будете использовать методы доступа - вы не сможете получить ничего быстрее, чем Class :: XSAccessor , поскольку он использует высокооптимизированный код C / XS для средств доступа.

Прокрутка собственного кода, генерирующего аксессоры, - наихудший из всех вариантов.

6
ответ дан 6 December 2019 в 06:14
поделиться

Нет никакой разницы, потому что:

sub Some_package::foo { ... }

- это просто сокращение для:

BEGIN { *Some_package::foo = sub { ... } }

Ссылка из perlmod

7
ответ дан 6 December 2019 в 06:14
поделиться

Оба подхода приводят к установке ссылки на подпрограмму в таблице символов во время компиляции. Поведение и производительность во время выполнения будут точно такими же. Может быть очень небольшая (т.е. незначительная) разница во времени компиляции.

Аналогичный подход заключается в создании средств доступа по запросу через AUTOLOAD , что оказывает небольшое влияние на время выполнения. Использование подхода AUTOLOAD также может изменить поведение таких вещей, как $ object-> can () .

Очевидно, создание методов скроет их от любой формы статического анализа, включая такие инструменты, как ctags.

2
ответ дан 6 December 2019 в 06:14
поделиться

Единственная разница - время запуска. Для простых схем генерации кода разницу будет трудно измерить. Для более сложных систем это может складываться.

Прекрасным примером этого в действии является Moose . Moose делает за вас всевозможные удивительные кодогенераторы, но это существенно влияет на время запуска. Этого достаточно, чтобы разработчики Moose работали над схемой для кэширования сгенерированного кода в файлах pmc и загрузки их вместо того, чтобы каждый раз восстанавливать код.

Также рассмотрите что-то вроде Class: : Struct . Он генерирует код с использованием строки eval (в последний раз я проверял). Даже в этом случае, поскольку это очень просто, он не вызывает значительного замедления при запуске.

2
ответ дан 6 December 2019 в 06:14
поделиться

Для справки в будущем, похоже, нет надежного способа сделать это без стороннего приложения. Pdftk ( http://www.accesspdf.com/pdftk/ ) оказался моим решением.

Сначала я сгенерировал файл FDF, как и раньше, а затем слил его в свой файл PDF, используя следующие Код PHP

header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="Download.pdf"');
passthru("pdftk file.pdf fill_form data.fdf output - ");
exit;

Это было намного проще, чем я думал. Это мгновенно избавляет от необходимости возиться с заголовками и расширениями файлов, чтобы гарантировать, что все браузеры правильно обрабатывают FDF, поскольку это просто заставляет браузер загружать файл PDF.

Если вы хотите, чтобы выходной файл PDF больше не редактировался, используйте

    passthru("pdftk file.pdf fill_form data.fdf output - flatten");

Приношу извинения, если это базовый материал, просто подумал, что я бы все это собрал в одном месте, чтобы люди не переживали головную боль, которую я перенес.

NB Если ваша переменная PATH не установлена, Попробуйте, например, следующее:

BEGIN {
    no strict 'refs';
    for my $a ("aaaa".."zzzz"){
        *{__PACKAGE__ . "::get_$a"} = sub { $_[0]->{$a}         };
        *{__PACKAGE__ . "::set_$a"} = sub { $_[0]->{$a} = $_[1] };
    }
}
print `ps -F -p $$`;  # adjust for your ps syntax

по сравнению с

sub get_aaaa { $_[0]->{aaaa}         }
sub set_aaaa { $_[0]->{aaaa} = $_[1] }
sub get_aaab { $_[0]->{aaab}         }
...
sub set_zzzy { $_[0]->{zzzy} = $_[1] }
sub get_zzzz { $_[0]->{zzzz}         }
sub set_zzzz { $_[0]->{zzzz} = $_[1] }
print `ps -F -p $$`;  # adjust for your ps syntax
2
ответ дан 6 December 2019 в 06:14
поделиться

Помимо отличные моменты, упомянутые другими, я также хотел бы добавить основной недостаток, который я обнаружил: все они отображаются как анонимные подпрограммы в профилировщике. По какой-то причине Devel :: DProf просто не знает, как вычислить имя.

Теперь я надеюсь , что более новый Devel :: NYTProf может работать лучше, но я не пробовал.

все они отображаются в профилировщике как анонимные подпрограммы. По какой-то причине Devel :: DProf просто не знает, как вычислить имя.

Теперь я надеюсь , что более новый Devel :: NYTProf может работать лучше, но я не пробовал.

все они отображаются в профилировщике как анонимные подпрограммы. По какой-то причине Devel :: DProf просто не знает, как вычислить имя.

Теперь я надеюсь , что более новый Devel :: NYTProf может работать лучше, но я не пробовал.

2
ответ дан 6 December 2019 в 06:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: