像 Slurpy 一样使用 Capture
Using a Capture like a Slurpy
我一直在阅读有关 Captures 的文章,这一段引起了我的兴趣:
Inside a Signature, a Capture may be created by prefixing a sigilless
parameter with a vertical bar |. This packs the remainder of the
argument list into that parameter.
这听起来很像 **@
(非扁平化)泥浆,所以编造了这个测试代码:
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 似乎确实具有性能优势。以这种方式使用 Capture
作为 slurpy 有不利的一面吗?我是否过度简化了比较?
A Capture
有两个槽,分别是 VM 级数组(位置参数)和散列(命名参数)。它的构造非常便宜,并且 - 由于 |c
样式参数在内部的各个位中很常见 - 已经得到很好的优化。由于捕获参数吞噬了位置参数和命名参数,因此任何命名参数都将被静默忽略。对于方法来说,这可能不是什么大问题,无论如何,不需要的命名参数将被静默地放入 %_
,但如果在 sub
上使用此构造可能是一个考虑因素,因为它不是纯粹的优化:它改变了行为。
**@c
案例分配一个 Array
,然后为每个传递的值分配一个 Scalar
容器,将它们放入 Scalar
容器和那些 Scalar
容器放入 Array
。这是合理的额外工作量。
这里没有考虑另一种情况,就是这个:
sub test3(**@c is raw){
1;
}
在@c
中放置一个List
,并设置它的元素直接引用传递的东西。这比没有is raw
的情况便宜了一点。从理论上讲,它的性能可能与 |c
这样的捕获参数一样好(如果不是更好的话);它可能只需要有人在编译器上工作来深入研究为什么它还没有。
总而言之,如果不关心具有可变 Array
传入参数的强制分项 and/or,那么添加 is raw
可能是比选择捕获参数更好的优化选择:参数处理语义更接近,它已经有点快了,将允许更自然的代码,并且未来有可能与 |c
.
一样快,如果不是更快的话。
我一直在阅读有关 Captures 的文章,这一段引起了我的兴趣:
Inside a Signature, a Capture may be created by prefixing a sigilless parameter with a vertical bar |. This packs the remainder of the argument list into that parameter.
这听起来很像 **@
(非扁平化)泥浆,所以编造了这个测试代码:
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 似乎确实具有性能优势。以这种方式使用 Capture
作为 slurpy 有不利的一面吗?我是否过度简化了比较?
A Capture
有两个槽,分别是 VM 级数组(位置参数)和散列(命名参数)。它的构造非常便宜,并且 - 由于 |c
样式参数在内部的各个位中很常见 - 已经得到很好的优化。由于捕获参数吞噬了位置参数和命名参数,因此任何命名参数都将被静默忽略。对于方法来说,这可能不是什么大问题,无论如何,不需要的命名参数将被静默地放入 %_
,但如果在 sub
上使用此构造可能是一个考虑因素,因为它不是纯粹的优化:它改变了行为。
**@c
案例分配一个 Array
,然后为每个传递的值分配一个 Scalar
容器,将它们放入 Scalar
容器和那些 Scalar
容器放入 Array
。这是合理的额外工作量。
这里没有考虑另一种情况,就是这个:
sub test3(**@c is raw){
1;
}
在@c
中放置一个List
,并设置它的元素直接引用传递的东西。这比没有is raw
的情况便宜了一点。从理论上讲,它的性能可能与 |c
这样的捕获参数一样好(如果不是更好的话);它可能只需要有人在编译器上工作来深入研究为什么它还没有。
总而言之,如果不关心具有可变 Array
传入参数的强制分项 and/or,那么添加 is raw
可能是比选择捕获参数更好的优化选择:参数处理语义更接近,它已经有点快了,将允许更自然的代码,并且未来有可能与 |c
.