Насколько дорого разыменование массива ref в Perl?
Интересно, создает ли Perl internals копию значений ref для создания массива? Например, следующее выводит последнее и первое значение строки с разделителями:
say @{[ split( q{|}, q{bar|is|foo} ) ]}[-1,0]; # STDOUT: foobarn
- генерирует ли операция сначала список через
split
и создает массив ref, а затем копирует значения массива ref в новый массив при разыменовании? - преобразует ли он текущий arrayref на месте?
Поскольку разыменование настолько распространено, что я уверен, что оно оптимизировано, я просто любопытно, насколько это дорого по сравнению с созданием массива из списка изначально, например:
my @parts = split q{|}, q{bar|is|foo};
say @parts[-1,0];
Цель: получение представления о базовых операциях без слишком глубокого проникновения в код
2 ответа:
Vol7ron> сколько стоит разыменование массива ref в Perl?
Ikegami> Вы делаете больше, чем просто разыменование массива.
Vol7ron> но вопрос все еще стоит
Опять же, это бесполезный вопрос. Альтернатива никогда не находится между простым разыменованием массива и чем-то еще.
Но поскольку вы настаиваете, для меня это 37 НС (37 миллиардных долей секунды).use Benchmark qw( cmpthese ); my %tests = ( deref => 'my @y = @$x;', none => 'my @y = @x;', ); $_ = 'use strict; use warnings; our $x; our @x; ' . $_ for values %tests; { local our @x = (); local our $x = \@x; cmpthese(-3, \%tests); }
Результат:
Rate deref none deref 3187659/s -- -12% none 3616848/s 13% --
Время, затраченное каждым дерефом = 1/3187659 с-1/3616848 с = 37 НС
Он крошечный! Разыменование массива занимает только 12% времени, необходимого для разыменования пустого массива и копирования его в другой массив!
Генерирует ли операция сначала список через split (1) и создает массив ref (2), а затем копирует значения массива ref в новый массив при разыменовании (3)?
Да,
split
возвращает список. За исключением скалярного контекста.
[ ... ]
не просто создает ссылка, она также создает массив и копирует в него значения.Нет, разыменование не копирует значения.
Было бы очень плохо, если бы ссылка превратилась во что-то другое. Что вы на самом деле имеете в виду?Преобразует ли он текущий arrayref на месте?
Вот эталон
#!/usr/bin/perl use strict; use warnings; use 5.010; use Benchmark qw(:all); my @list = ('foo')x1_000_000; my $str = join('|',@list); my $count = -2; cmpthese($count, { 'deref' => sub { my $parts = [ split( q{\|}, $str ) ]; my @res = @$parts[-1,0]; }, 'array' => sub { my @parts = split q{\|}, $str; my @res = @parts[-1,0]; }, });
Я просто меняю
say
на назначение.
Windows 7, perl 5.14.2Rate deref array deref 2.02/s -- -38% array 3.23/s 60% --
В зависимости от окружения, я получаю
Linux 64 bit, perl 5.14.2Rate deref array deref 3.00/s -- -35% array 4.65/s 55% --
И Linux 32 bit, perl 5.8.4
Rate array deref array 1.96/s -- -35% deref 3.00/s 53% --