Могу ли я сказать Perl, что некоторые данные неизменны для ускорения процесса? - PullRequest
1 голос
/ 19 мая 2009

Perl действительно хорош для написания программ разбора строк / файлов, которые мне обычно нужно делать. Что мне действительно нравится, так это то, что я пишу быстрые сценарии и одноразовый код по сравнению с C / C ++ / JAVA. Тем не менее, я хочу узнать, как ускорить процесс.

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

Я действительно хочу рассматривать некоторые строки как (const char *). Я уверен, что нам всегда не нужно, чтобы все было std :: string со всем задействованным багажом (предположим, что std :: string аналогична строке Perl). Могу ли я дать подсказку Perl, чтобы сделать это на некоторых строках?

Я помню, как читал в какой-то статье (пожалуйста, прокомментируйте, если вы можете ее разместить), что вы можете намекнуть Perl, что вы не будете изменять какую-то переменную, и, таким образом, он удаляет дополнительный багаж, который в противном случае требуется, если вы его изменили, и т. Д. .

Я считаю, что переменные Perl имеют два внутренних указателя на одну и ту же переменную Perl - один может хранить число, а другой - строку (массив символов). Могу ли я всегда сказать Perl, чтобы выбрать один из всех? Могу ли я заставить Perl обрабатывать некоторые строки как (const char *), чтобы они не помечали функциональность, необходимую для их изменения?

Например, я где-то читал (может быть, в той же статье?), Что unpack () быстрее, чем substr (), потому что substr () возвращает lvalue, так что вы также можете работать с ним. Например, если я хочу заменить первые два символа строки на 'ef', я могу написать:

substr(string, 0, 2) = 'ef'; # string now begins with 'ef'

Следовательно, если я не использую эту особенность функции substr (), мне лучше использовать substr?

Я только что разглагольствовал?

Ответы [ 4 ]

16 голосов
/ 19 мая 2009

Вы можете установить флаг SvREADONLY для переменной с помощью Readonly::XS, но это не повышает эффективность. Эффективность достигается за счет выбора правильного алгоритма, а не подсказок компилятора. Если вы хотите, чтобы ваш код был быстрее / занимал меньше памяти, профилируйте его (см. Devel::NYTProf). Когда вы обнаружите узкое место, используйте другой алгоритм или переключитесь на XS.

Кроме того, если вы собираетесь что-то оптимизировать, убедитесь, что результат действительно быстрее, вот так: substr vs unpack:

            Rate unpack substr
unpack 2055647/s     --   -74%
substr 7989875/s   289%     --

Вот код теста.

#!/usr/bin/perl

use strict;
use warnings;

use Benchmark;

my %subs = (
    unpack => sub { return unpack "a3", "foobarbaz" },
    substr => sub { return substr "foobarbaz", 0, 3 }
);

for my $sub (keys %subs) {
    print "$sub => ", $subs{$sub}(), "\n";
}

Benchmark::cmpthese -1, \%subs;
7 голосов
/ 19 мая 2009

в целом:

Используйте хорошие алгоритмы и не оптимизируйте, если в этом нет необходимости. Если это так, профилируйте ваш код и сравните ваши изменения. Это хорошее время, чтобы рассмотреть XS или Inline :: C при необходимости.

a (const *) char equvialent:

use constant Foo => 'bar'; создает минимальную подпрограмму, которая может быть встроена компилятором perl. Вы также можете создавать свои собственные встроенные постоянные функции

избегать дополнительного копирования:

Типичная идиома perl делает некоторое «дополнительное» копирование:

sub foo {
    my $bar = shift;

    ..do stuff with $bar...
}

Многие люди не понимают, что Perl передает аргументы подпрограммам по ссылке. @_ содержит псевдонимов для аргументов подпрограммы.

Таким образом, вы можете избежать копирования своих аргументов, работая с @_ напрямую:

foo( $big_scalar );

sub foo {
    ..do stuff with $_[0]...
    .. sneakily risk modifying $big_scalar ..
}

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

Если мне нужно переместить большой кусок данных, но я не собираюсь его изменять, я обычно передаю его явно по ссылке, а не возню @_;

foo( \$big_scalar );
sub foo {
    my $bar = shift;
    ... do stuff with $$bar ...
    ... can modify $big_scalar, but the pass by ref is explicit ...
}

[P] оптимизация отсрочки - корень всего зла

По крайней мере, так довольно классно сказал Дональд Кнут. В этом утверждении много мудрости.

Неправильная оптимизация (код, который якобы является оптимизацией, но не очень), тоже довольно плох.

Код для ясности в первую очередь. Обязательно профилируйте свой код, чтобы найти узкие места. Обязательно сравните ваши оптимизации, чтобы убедиться, что они работают. Документируйте свой оптимизированный код, держите под рукой некоторый тестовый код - завтрашний компилятор может не отвечать так же, как сегодняшний.

3 голосов
/ 19 мая 2009

Я с Chas, бенчмарк и профилировать ваш код в первую очередь. Я действительно сомневаюсь, что копирование строк - это ваше узкое место, и вы потратите очень много времени на небольшую выгоду. Даже если копирование строк оказывается узким местом, сначала найдите в своем коде некорректный алгоритм. Одним из значительных потенциальных повышений производительности Perl по сравнению с C и Java является то, что он настолько быстро пишет код, что оставляет вам много дополнительного времени для профилирования, оптимизации и улучшения алгоритма.

Если копирование строк действительно является вашим узким местом, рассмотрите возможность передачи больших строк в качестве ссылок. Моральный эквивалент строкового указателя на C. Это предотвратит копирование. Не забудьте разыменовать их, прежде чем использовать их.

sub foo {
    my $ref = shift;

    print $$ref;
}

$string = "Some string";
foo(\$string);
0 голосов
/ 19 мая 2009

Я помню, как читал в какой-то статье (пожалуйста, прокомментируйте, если вы можете ее разместить), что вы можете намекнуть Perl, что вы не будете изменять какую-то переменную, и, таким образом, он удаляет дополнительный багаж, который в противном случае требуется, если вы изменили его и т. Д. 1002 *

Буду ли я прав, предполагая, что вы говорите о ' используйте константу ...'?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...