6

我很好奇 Perl 内部是否会创建 ref 值的副本来创建数组?例如,以下输出分隔字符串的最后一个值和第一个值:

say @{[ split( q{\|}, q{bar|is|foo} ) ]}[-1,0];     # STDOUT: foobar\n
  • 该操作是否首先通过生成列表split并创建数组 ref,然后在取消引用时将数组 ref 的值复制到新数组中?
  • 它会变形当前的arrayref吗?

因为取消引用是如此普遍,我确信它已经过优化,我只是好奇它与最初从列表中创建一个数组相比有多昂贵,例如:

my @parts = split q{\|}, q{bar|is|foo};
say @parts[-1,0];

目的:了解底层操作而无需深入了解代码

4

2 回答 2

3

这是一个基准

#!/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 位,perl 5.14.2

        Rate deref array
deref 3.00/s    --  -35%
array 4.65/s   55%    --

和 Linux 32 位,perl 5.8.4

        Rate array deref
array 1.96/s    --  -35%
deref 3.00/s   53%    --
于 2013-09-24T14:32:05.840 回答
1

vol7ron> 在 Perl 中取消引用数组引用有多昂贵?

ikegami> 您所做的不仅仅是取消对数组的引用。

vol7ron> 但问题仍然存在

同样,这是一个无用的问题。替代方案永远不会在简单地取消引用数组和其他东西之间。

但既然你坚持,对我来说它是 37 ns(十亿分之一秒)。

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

每个 deref 花费的时间 = 1/3187659 s - 1/3616848 s = 37 ns

它很小!取消引用数组只占取消引用空数组并将其复制到另一个数组的时间的 12%!

该操作是否首先通过 split (1) 生成列表并创建数组 ref (2),然后在取消引用 (3) 时将数组 ref 的值复制到新数组中?

  1. 是的,split返回一个列表。除了在标量上下文中。

  2. [ ... ]不只是创建一个引用,它还创建一个数组并将值复制到其中。

  3. 不,取消引用不会复制值。

它会变形当前的arrayref吗?

如果引用变成了其他东西,那将是非常糟糕的。你到底是什么意思?

于 2013-09-25T02:16:42.030 回答