在Perl中取消引用数组ref的代价有多高?

在Perl中取消引用数组ref的代价有多高?,perl,dereference,Perl,Dereference,我很好奇Perl内部是否会创建ref值的副本来创建数组?例如,以下输出分隔字符串的最后一个和第一个值: say @{[ split( q{\|}, q{bar|is|foo} ) ]}[-1,0]; # STDOUT: foobar\n 该操作是否首先通过split生成一个列表并创建一个数组ref,然后在取消引用时将数组ref的值复制到一个新数组中 它是否变形了当前的arrayref 因为解引用非常常见,我确信它是经过优化的,我只是好奇它与最初从列表中创建数组相比有多昂贵,比如:

我很好奇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];

目的:了解底层操作,而不是深入代码

这里是一个基准

#!/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];
    },
});
我只是把
改成一个任务。
Windows 7,perl 5.14.2

        Rate deref array
deref 2.02/s    --  -38%
array 3.23/s   60%    --
        Rate deref array
deref 3.00/s    --  -35%
array 4.65/s   55%    --
根据环境的不同,我得到了
Linux 64位,perl 5.14.2

        Rate deref array
deref 2.02/s    --  -38%
array 3.23/s   60%    --
        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%    --
vol7ron>在Perl中取消引用数组ref的代价有多高


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

但是问题仍然存在

同样,这是一个无用的问题。另一种选择决不是简单地取消对数组的引用,而是进行其他操作

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

结果:

           Rate deref  none
deref 3187659/s    --  -12%
none  3616848/s   13%    --
每个deref所用的时间=1/3187659秒-1/3616848秒=37纳秒

它很小!取消对阵列的引用只占取消对空阵列的引用并将其复制到另一个阵列所需时间的12%

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

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

  • […]
    不仅创建引用,还创建数组并将值复制到其中

  • 不,取消引用不会复制值

  • 它是否变形了当前的arrayref


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

    顺便说一句,通常的方法是
    say+(split/\\\124;/,'bar | is | foo')[-1,0]
    @choroba:是的,我发现这更清楚,但我发现人们不熟悉这个符号,也不知道如何查找它,因为
    +
    非常普遍,你所做的不仅仅是取消对数组的引用。您还创建了一个数组和一个引用,并将列表分配给该数组。@choroba:(看起来我的其他注释没有保存),但我更可能使用括号而不是一元加号;例如
    say((split/\\|/,'bar | is | foo')[-1,0])@ikegami是;从这个例子来看,你是100%绝对正确的;除了我取消引用一个引用,而不是一个数组;)但问题仍然存在,我只得到1%的差距。@mpapec:我在5.10.1中得到了3%。
    my@res=(split/\\|/,'bar|is | foo')[-1,0]行分别得到了63和58。@mpapec:我在Perl5.14.2上得到了可比的数字,但在Perl5.8.8上只有3%的差异。显然,数组版本在这两者之间得到了优化;cmpthese(-2,{deref=>sub{[split q{\\\},$string]}[-1,0];},array=>sub{@parts=split q{\\\},$string;@parts[-1,0];}})
    <代码>数组:88%;deref:-47%
    如果看起来像,请发表评论wrong@mpapec:好的,我得到了大致相同的差异。同样,您只是将费用转换为每秒的计算单位。它有多大的记忆差异?如果内存中有200MB,并且在将ref转换为数组时会加倍,我会将加倍称为开销。除了实时/cpu时间之外,我还可以想到许多会影响费用的因素。我尊重你,但你说这是一个无用的问题,这一事实使我对否决票进行了辩论——你并不在乎:)至于这些例子,我同意它们可能不是最好的例子来说明我提出的问题。因为它是一个数组引用,而引用通常只是一个指针,所以可能没有费用,它可能已经附加了所有的方法,区别在于在它前面粘贴了一个符号——这是一个可以接受的答案;然而,这是Perl,当从array ref转到array时,可能会发生其他事情。我从来没有说过这不是一个合适的例子。我会说没有合适的例子。永远不会在取消引用和不取消引用之间或在取消引用和其他内容之间进行选择。因此,给定
    $x=[0..10]
    ,以下选项将不是有效的选择<代码>$x->[2]
    vs
    {$x}[2]
    作为对你答案的回应,我想我得到了你关于复制的底部答案#3。在回答“变形”问题时,我很好奇通过取消引用是否会出现任何多态性。如果ref真的只是指针,那么我不认为这是真的,但由于Perl具有潜在的魔力,这就是我为什么要问的原因。