鉴于一些代码对1到500000的每个数字进行了一些数学/转换,我们有以下选项:
简单的循环:for ^500000 -> $i { my $result = ($i ** 2).Str; }.在我不科学的基准测试中,这需要2.8秒.
最规范的并行版本在a中完成每一项工作Promise,然后等待结果.await do for ^500000 -> $i { start { my $result = ($i ** 2).Str; } }需要19秒.这很慢!创建一个新的promise必须有太多的开销才能进行这样一个简单的计算.
使用并行map操作相当快.在2.0秒时,操作似乎几乎不足以利用并行化:(^500000).race.map: -> $i { my $result = ($i ** 2).Str; }
第三种选择似乎最好.不幸的是,它看起来像一个黑客.我们不应该map在sink上下文中编写迭代代码,因为在源代码中读取"map"的其他人可能会认为目的是构建一个列表,这根本不是我们的意图.使用map这种方式的沟通很差.
有没有任何规范的快速方法来使用Perl 6的内置并发?如果一个超级运算符可以接受一个块而不仅仅是函数,那么它将是完美的:
(^500000)».(-> $i { my $result = ($i ** 2).Str; }) # No such method 'CALL-ME' for invocant of type 'Int'
Run Code Online (Sandbox Code Playgroud)
如果你想使用超级或竞赛操作,你必须拼写它hyper for @blah.hyper(:batch(10_000))或race for @blah.race(:batch(10_000)).或者没有参数:hyper for @blah,race for @blah.
这是因为决定你可能有这样的代码for some-operation() { some-non-threadsafe-code },其中some-operation一个图书馆或某事的一部分.现在你不能再告诉for循环是否可以包含线程不安全的代码,即使你知道库HyperSeq在那个时间点没有返回,如果库作者想出这个好主意怎么办?some-operation通过加强它来加快速度?
这就是为什么在代码所在的位置需要一个"并行运行此for循环"的能指的原因,而不仅仅是创建序列的地方.