среда, 25 августа 2010 г.

Инкремент такой инкремент : инициализируй числовую перменную как строку и потеряй 20% скорости :)


Заголовок конечно провокационный, но бенчмарк показывает, что вариант с числовой инициализацией переменной на 20% быстрее(тестировал на 5.12).


#/usr/bin/perl -w
use v5.10;
use strict;
use warnings;

use Benchmark ':all';

cmpthese(
    -5, {
        integer_init => sub {
            my $i = 0;
            $i++ for ( 1 .. 10000 );

        },

        string_init => sub {
            my $i = '0';
            $i++ for ( 1 .. 10000 );
        },
    } );

#               Rate  string_init integer_init
#string_init  1769/s           --         -18%
#integer_init 2147/s          21%           --
    

Разгадка данной особенности довольно проста. При инициализации Perl сохраняет число, как строку. И результат инкремента сохраняет в строковом виде!!! Именно так :).

perl -MDevel::Peek -e 'my $i = "1"; print Dump $i;  $i++; print Dump $i;'
SV = PV(0x604bc8) at 0x62d318
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x61ec50 "1"\0
  CUR = 1
  LEN = 8

SV = PV(0x604bc8) at 0x62d318
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x61ec50 "2"\0
  CUR = 1
  LEN = 8


С декрементом такого не будет. В принципе любая числовая операция (даже числовое сравнение, например $i < 100) заставит Perl хранить число как число,  а не как строку.

for (my $i='10'; $i < 20; $i++) {} # это будет работать нормально, поскольку есть числовое сравнение.

5 коммент.:

Анонимный комментирует...

my $i = '0';
Почему же он не должен сохранять в строковом виде?

Такой же инкримент вполне работоспособный:
perl -e "my$q='AA'; for(1..5){$q++; print ' '.$q;}"
AB AC AD AE AF

Анонимный комментирует...

Вот здесь более понятно, то Перл работает со строками, а не с числами:
perl -e "for(my$q='AA'; $q ne'BB'; $q++) {print $q.\"\n\";}"

Анонимный комментирует...

КАК?!! Как Вы до этого примера додумались? :)))

koorchik комментирует...

При инициализации строкой - он должен сохранять строку, но после числового инкремента мог бы и как число хранить ( операция числового сравнения приводит же строку к числу). Если мы инициализировали числом, то Perl работает с числами. Работа с числом быстрее.

В текущей реализации я вижу следующие бонусы:
1. Общий алгоритм инкремента для буквенных строк и чисел. Буквенный инкремент - полностью аналогичен, только используется другая основа для системы исчисления(26 вместо 10) и другие знаки ( a..z вместо 0..9)
2. Не нужно работать с флоатами.
3. В большинстве случаем мы все равно используем переменную в числовом сравнении.
4. Возможно экономия памяти(только возможно :) ), поскольку при переходе на числовое хранение, строка в памяти все равно остается.
perl -MDevel::Peek -e '$i = "z"x1000; $i = 9999; print Dump $i'

В любом случае идея поста заключается том, что работать с числами нужно как с числами :)

koorchik комментирует...

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

Отправить комментарий

Не забудьте добавить себя в постоянные читатели и включить уведомления о новых комментариях, либо воспользуйтесь RSS каналом ;)