【问题标题】:Using a Capture like a Slurpy像 Slurpy 一样使用 Capture
【发布时间】:2019-04-16 13:38:00
【问题描述】:

我一直在阅读关于 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 显然具有性能优势。以这种方式使用 Capture 作为 slurpy 有不利的一面吗?我是否过度简化了比较?

【问题讨论】:

  • 当使用子例程时,捕获 |c 将采用非扁平化 slurpy **@c 不会采用的“意外命名参数”。
  • 我想真正的问题是你打算用 c 做什么?
  • @CurtTilmes 没有直接的计划,只是为了了解 Captures 并寻找简单的性能提升,以便多次重复调用 subs
  • 我不知道有什么特别的缺点 - 如果它适用于您的情况,请使用它!

标签: capture raku


【解决方案1】:

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

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

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

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

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

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

【讨论】:

  • 使用 ` |c, +@c, **@c` 和 **@c is raw 的快速测试给出了 0.8427187, 2.593368, 2.8757735 and 2.8949438 的持续时间。这可能取决于用例,但Capture 似乎是这个简单测试中最快的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2016-08-27
  • 1970-01-01
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多