首页 > 解决方案 > 像 Slurpy 一样使用 Capture

问题描述

我一直在阅读有关Captures的内容,这一段让我很感兴趣:

在签名中,可以通过在无符号参数前加上竖线 | 来创建捕获。这会将参数列表的其余部分打包到该参数中。

这听起来很像一个**@(非扁平化)slurpy,所以这编造了这个测试代码:

my $limit=1_000_000;
my @a=1 xx 10000;
my @b=-1 xx 10000;

sub test1(|c){
    1;
};

sub test2(**@c){
    1;
};
{ 
    for ^$limit {
        test1(@b,@a);
    }
    say now - ENTER now;
}
{
    for ^$limit {
        test2(@b,@a);
    }
    say now - ENTER now;
}

样本运行给出了每个测试块的持续时间:

0.82560328                                                                                                                                                                                                                                                                                                         
2.6650674 

Capture 显然具有性能优势。以这种方式使用 aCapture作为 slurpy 有不利的一面吗?我是否过度简化了比较?

标签: captureraku

解决方案


ACapture有两个插槽,包含一个 VM 级别的数组(位置参数)和哈希(命名参数)。它的构造非常便宜,并且 - 由于|c样式参数在内部的各个部分中都很常见 - 已经得到了很好的优化。由于捕获参数会同时占用位置参数和命名参数,因此任何命名参数都将被静默忽略。对于方法来说,这可能不是什么大问题,其中不需要的命名参数无论如何都会被静默放置%_,但如果在 a 上使用此构造可能是一个考虑因素sub,因为它不是纯粹的优化:它会改变行为。

**@c案例分配一个Array,然后Scalar为每个传递的值分配一个容器,将它们放入Scalar容器中,将这些Scalar容器放入Array. 这是合理的额外工作量。

这里没有考虑另一种情况,就是这个:

sub test3(**@c is raw){
    1;
}

这放置了一个Listin @c,并将其元素设置为直接引用传递的内容。这比没有的情况要便宜一些is raw。从理论上讲,它的性能可能与 - 如果不优于 - 捕获参数一样好,例如|c; 它可能只需要有人在编译器上工作来深入了解为什么它还没有。

总之,如果不关心强制逐项和/或具有可变Array的传入参数,那么添加is raw可能是比选择捕获参数更好的优化选择:参数处理语义更接近,它已经有点快,将允许更多自然代码,并且未来有可能与|c.


推荐阅读