Производительность локальной переменной и доступа к массиву - PullRequest
0 голосов
/ 09 октября 2018

Я проводил некоторые тесты производительности Perl и столкнулся с делом, которое мне показалось странным.Предположим, у вас есть функция, которая использует значение из массива несколько раз.В этом случае вы часто видите некоторый код в виде:

sub foo {
  my $value = $array[17];

  do_something_with($value);
  do_something_else_with($value);
}

Альтернатива - вообще не создавать локальную переменную:

sub foo {
  do_something_with($array[17]);
  do_something_else_with($array[17]);
}

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


Представьте себе мое удивление, когда эта тестовая программа показаланапротив.На моей машине повторный поиск в массиве на самом деле быстрее , чем сохранение результата, пока я не увеличу ITERATIONS до 7;другими словами, для меня создание локальной переменной имеет смысл только в том случае, если она используется по крайней мере 7 раз!

use Benchmark qw(:all);

use constant { ITERATIONS => 4, TIME => -5 };

# sample array
my @array = (1 .. 100);

cmpthese(TIME, {
  # local variable version
  'local_variable' => sub {
    my $index = int(rand(scalar @array));
    my $val = $array[$index];
    my $ret = '';

    for (my $i = 0; $i < ITERATIONS; $i ++) {
       $ret .= $val;
     }

    return $ret;
  },

  # multiple array access version
  'multi_access' => sub {
    my $index = int(rand(scalar @array));
    my $ret = '';

    for (my $i = 0; $i < ITERATIONS; $i ++) {
      $ret .= $array[$index];
    }

    return $ret;
  }
});

Результат:

                   Rate local_variable   multi_access
local_variable 245647/s             --            -5%
multi_access   257907/s             5%             --

Это не ОГРОМНОЕ различие, но оноподнимает мой вопрос: почему медленнее создать локальную переменную и кэшировать поиск в массиве, чем снова выполнять поиск? Читая другие сообщения SO, я видел, что другие языки / компиляторы действительно имеютожидаемый результат, а иногда даже преобразовать их в один и тот же код.Что делает Perl?

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

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

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

my $index = int(rand(scalar @array));
my $val = 0; # <- this is new
$val = $array[$index];
my $ret = '';

... код подвергается дополнительному штрафу в 5% скорости по сравнению с версией для одного назначения - даже если он ничего не делаетно фиктивное присвоение переменной.

Я также проверил, не вызвало ли область действия настройку / разрыв $var, чтобы снизить производительность, переключив ее на глобальную, а не на локальную область.Разница незначительна (см. Комментарии к @zdim выше), указывая в сторону от конструкции / разрушения в качестве узкого места производительности.


В конце концов, моя путаница была основана на ошибочные предположения , что скалярное назначение должно быть быстрым .Я привык работать в C, где копирование значения в локальную переменную является чрезвычайно быстрой операцией (1-2 инструкции asm).

Как оказалось, в Perl это не так (хотя яне знаю точно почему, это нормально).Скалярное присваивание является относительно «медленной» операцией ... Что бы ни делали внутренние компоненты Perl, чтобы добраться до n-го элемента объекта Array, на самом деле это довольно быстро по сравнению.«Умножение и сложение», о котором я упоминал в первом посте, по-прежнему гораздо менее трудоемкий, чем код для скалярного присваивания.

Вот почему требуется так много поисков, чтобы соответствовать производительности кэширования результата: просто присваиваниепеременная «кеш» примерно в 7 раз медленнее (для моей настройки).

0 голосов
/ 09 октября 2018

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

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

...