Насколько дорого разыменование массива 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 6

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)?

  1. Да, split возвращает список. За исключением скалярного контекста.

  2. [ ... ] не просто создает ссылка, она также создает массив и копирует в него значения.

  3. Нет, разыменование не копирует значения.

Преобразует ли он текущий 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.2

        Rate deref array
deref 2.02/s    --  -38%
array 3.23/s   60%    --

В зависимости от окружения, я получаю
Linux 64 bit, perl 5.14.2

        Rate 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%    --