Perl: Почему медленнее объявлять (мои) переменные внутри цикла? - PullRequest
6 голосов
/ 23 июля 2010

В чем разница от POV переводчика между следующими программами:

#!/usr/bin/perl -w

use strict;

for (1..10000000) {
    my $jimmy = $_**2;
}

и

#!/usr/bin/perl -w

use strict;

my $jimmy;
for (1..10000000) {
    $jimmy = $_**2;
}

отчеты "time" для первой программы:

real    0m1.519s
user    0m1.513s
sys     0m0.004s

и для второго:

real    0m1.023s
user    0m1.012s
sys     0m0.002s

Ответы [ 5 ]

10 голосов
/ 24 июля 2010

Объявление my в Perl имеет два основных эффекта; один во время компиляции (в котором он выделяет слот на блокноте, содержащем подпрограмму, и следит за тем, чтобы все ссылки на это имя в соответствующей области видимости были разрешены в этот конкретный слот блокнота), и один во время выполнения (в котором он сбрасывает значение этот слот пэда до undef или до какого-то определенного значения, если вы написали my $var = foo).

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

3 голосов
/ 24 июля 2010

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

my @closures;
my $jimmy;

for (1 .. 10) {
    $jimmy = $_** 2;
    push @closures, sub {print "$jimmy\n"};
}

и этот:

my @closures;

for (1 .. 10) {
    my $jimmy = $_** 2;
    push @closures, sub {print "$jimmy\n"};
}

В каждом случае код создает серию ссылок на код, но в первом примере, поскольку все ссылки на код ссылаются на один и тот же $jimmy, каждый из них при вызове выдает 100 Во втором примере каждый код ref будет печатать различное число (1, 4, 9, 16, 25, ...)

Так что в этом случае разница во времени не имеет большого значения, так как два блока кода делают очень разные вещи.

2 голосов
/ 23 июля 2010

Первый цикл пытается сделать объявление переменной для каждой итерации цикла и может привести к ненужному времени обработки.

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

1 голос
/ 23 июля 2010

Ну, во-первых, есть проблема, что вы объявляете новую переменную с каждой итерацией.

Во-вторых, есть большая проблема определения объема.

Попробуйте добавить эту строку после for в каждом из них и посмотрите, что произойдет:

print $jimmy;

И попробуйте это также:

my $jimmy;
for (1..10000000) {
    my $jimmy = $_**2;
}
print $jimmy;

Немного подробнее:

A my объявляет перечисленные переменные в быть локальным (лексическим) для вмещающего блок, файл или eval. Если более одного значение указано, список должен быть в скобках.

http://perldoc.perl.org/functions/my.html

Вы, вероятно, найдете это также полезным чтением:

http://perldoc.perl.org/perlsub.html#Private-Variables-via-my%28%29

0 голосов
/ 24 июля 2010
  1. Объявление my вне цикла приводит к тому, что объявление происходит один раз. Во время объявления perl резервирует память для этой переменной.

  2. Объявление my внутри цикла приводит к тому, что объявление происходит на каждом интервале цикла.

my - это ответ Perl на локальное объявление переменной - local использовался для чего-то другого и не означает то же самое, что он будет означать в C. Когда вы объявляете переменную внутри цикла, она объявляется в локальной области к блоку цикла, где блок начинается / заканчивается в каждом интервале. Переменная не только объявлена, но также может быть очищена (разыменована и / или установлена ​​на undef) в конце блока (хотя это отличается от версий Perl).

Переменные, объявленные вне блока цикла, считаются «глобальными» (не в буквальном смысле, а в смысле блока цикла). Эти переменные повторно используют свои места в памяти, вместо того, чтобы искать новые адреса.

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