sid*_*com 7 variables concurrency perl6
是否安全,在promises之间共享数组,就像我在下面的代码中所做的那样?
#!/usr/bin/env perl6
use v6;
sub my_sub ( $string, $len ) {
my ( $s, $l );
if $string.chars > $len {
$s = $string.substr( 0, $len );
$l = $len;
}
else {
$s = $string;
$l = $s.chars;
}
return $s, $l;
}
my @orig = <length substring character subroutine control elements now promise>;
my $len = 7;
my @copy;
my @length;
my $cores = 4;
my $p = @orig.elems div $cores;
my @vb = ( 0..^$cores ).map: { [ $p * $_, $p * ( $_ + 1 ) ] };
@vb[@vb.end][1] = @orig.elems;
my @promise;
for @vb -> $r {
@promise.push: start {
for $r[0]..^$r[1] -> $i {
( @copy[$i], @length[$i] ) = my_sub( @orig[$i], $len );
}
};
}
await @promise;
Run Code Online (Sandbox Code Playgroud)
Jon*_*ton 14
这取决于你如何定义"数组"和"共享".就数组而言,有两种情况需要单独考虑:
my @a[$size]); 这包括具有固定尺寸的多维数组(例如my @a[$xs, $ys]).这些具有有趣的特性,支持它们的内存永远不必调整大小.my @a),按需增长.随着时间的推移,它们实际上随着时间的推移使用了大量的内存块.就共享而言,还有三种情况:
然后我们可以总结如下安全性:
| Fixed size | Variable size |
---------------------+----------------+---------------+
Read-only, non-lazy | Safe | Safe |
Read/write or lazy | Safe * | Not safe |
Run Code Online (Sandbox Code Playgroud)
*表示警告虽然从Perl 6的角度来看是安全的,但你当然必须确保你没有用相同的指数做相互矛盾的事情.
总而言之,固定大小的数组你可以安全地共享和分配给不同线程的元素"没问题"(但要注意虚假共享,这可能会让你为此付出沉重的性能损失).对于动态数组,只有在它们被共享期间才能读取它们才是安全的,即使这样,如果它们不是懒惰的(尽管给定的数组赋值主要是渴望,你不太可能遇到这种情况)意外地).即使是针对不同的元素,写入也会导致数据丢失,崩溃或其他不良行为,这可能会导致操作的增长.
因此,考虑到原始示例,我们看到my @copy;并且my @length;是动态数组,因此我们不能在并发操作中写入它们.但是,这种情况会发生,因此可以确定代码不安全.
已经在这里发布的其他帖子在指向更好的方向方面做得不错,但没有一个能够指出血腥的细节.
只需使用start语句前缀标记的代码返回值,以便Perl 6可以为您处理同步.这个功能的重点在哪一点.
然后,您可以等待所有Promises,并使用await语句获取所有结果.
my @promise = do for @vb -> $r {
start
do # to have the ?for? block return its values
for $r[0]..^$r[1] -> $i {
$i, my_sub( @orig[$i], $len )
}
}
my @results = await @promise;
for @results -> ($i,$copy,$len) {
@copy[$i] = $copy;
@length[$i] = $len;
}
Run Code Online (Sandbox Code Playgroud)
该start声明前缀只是排序的切向相关的并行性.
当你使用它时,你说,"我现在不需要这些结果,但可能会在以后".
这就是它返回Promise(异步)的原因,而不是Thread(并发)
允许运行时延迟实际运行该代码,直到您最终要求结果,即使这样,它也可以在同一个线程中按顺序执行所有这些操作.
如果实现实际上这样做,就可能造成类似僵局,如果你不是轮询承诺通过不断调用它的.status方法等待它从更改Planned到Kept或Broken,然后才要求其结果.
这是默认调度程序如果有任何备用线程将开始处理任何Promise代码的部分原因.
我建议观看jnthn的演讲"Perl 6中的Parallelism,Concurrency和Asynchrony".
幻灯片
这个答案适用于我对MoarVM情况的理解,不知道JVM后端(或Javascript后端fwiw)的现状是什么.
$ perl6 -e 'my $i = 0; await do for ^10 { start { $i++ for ^10000 } }; say $i'
46785
这同样适用于更复杂的数据结构,例如数组(例如,缺少值被推送)和散列(缺少键被添加).
因此,如果您不介意丢失更新,那么从多个线程更改共享数据结构应该可行.如果您确实想到缺少更新,我认为这是您通常想要的,您应该以不同的方式设置算法,如@Zoffix Znet和@raiph所建议的那样.