2017-05-04 11 views
6

次のコードで行ったような約束事の間で配列を共有することは安全ですか?スレッド間で配列を共有するのは安全ですか?

#!/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; 
+0

約束のポイントは、何かを返すという約束で、意図的に 'start'ステートメントプレフィックスから有用なものを返すわけではありません。 –

+0

しかし、 'start'は何かを返すだけです。私は並行処理の部分に興味がありますので、CPUのすべてのコアが動作するように並列にコードを実行してください。 –

+1

私が言っていることは、レンチを拾い、それを爪の中に入れて使うことに似ています。どの作品、...私は推測する。 –

答えて

14

「配列」と「共有」の定義方法によって異なります。これまでの配列が行くように、個別に検討する必要がある2つの場合がある:

  • 固定サイズの配列(my @a[$size]を宣言したが)。これは、固定寸法(例えば、my @a[$xs, $ys])を有する多次元配列を含む。これらは、バッキングメモリが決してサイズ変更されないという興味深い特性を持っています。
  • オンデマンドで成長するダイナミックアレイ(my @aと宣言)。これらは、実際には成長していくにつれて、時間の経過と共に多くのチャンクを使用しています。

これまで共有が行くように、3例もありますが原因で、

  • 複数のスレッドがその寿命にわたって配列に触れる場合には、一つだけが今までの時間でそれに触れることができますいくつかの同時実行制御メカニズムまたは全体的なプログラム構造。この場合、配列は「配列を使用した並行操作」という意味では決して共有されないため、データ競合を起こす可能性はありません。
  • 読み取り専用で、遅延していないケース。これは、複数の並行操作がレイジーではない配列にアクセスするが、読み取り専用である。
  • 読み書きの場合(レイジー評価を要求する配列が配列に割り当てられているために読み込みが実際に発生する場合を含みますが、固定サイズの配列では遅延が発生しないため、これは決して発生しません)。次のよう

はその後、我々は、安全性をまとめることができます。

     | Fixed size  | Variable size | 
---------------------+----------------+---------------+ 
Read-only, non-lazy | Safe   | Safe   | 
Read/write or lazy | Safe *   | Not safe  | 

それは、ビューのはPerl 6の視点から安全ですが、あなたはもちろん、あなたがやっていないことを確認しなければならないという警告を表示*同じ指数で競合するもの。

要約すると、固定サイズの配列を安全に共有し、異なるスレッドからの要素に「問題なし」を割り当てることができます(誤った共有に注意してください。動的配列の場合、共有されている期間に読み込みを行うだけで、それでも怠け者でない場合でも安全です(指定された配列の割り当てはほとんど熱心ですが、その状況にぶつかる可能性は低いです事故によって)。さまざまな要素にも書き込むことで、データ損失、クラッシュ、または増大する操作による他の悪い振る舞いを危険にさらします。

したがって、元の例を考えてみると、my @copy;my @length;は動的配列なので、並行操作でそれらに書き込まないでください。しかし、それが起こるので、コードは安全でないと判断することができます。

他の投稿は、ここでは、より良い方向を指し示すというまともな仕事をしていますが、誰もその細部を釘付けにしていません。真剣

5

ちょうどPerl 6のは、あなたのための同期を処理できるように値を返すstart文の接頭辞でマークされたコードを持っています。その機能の全体的なポイントはどれですか。
その後、すべての約束を待って、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; 
} 

startの文の接頭辞は、並列にのみソートの接線方向に関連しています。
これを使用すると、「私は今、これらの結果は必要ないが、おそらく後になるだろう」と言っている。それはPromise(非同期)を返し、あなたが最終的な結果を求める、とさえ、それができるまでないThread(同時性)

ランタイムが実際にそのコードを実行している遅らせることが許可されている理由である

それらのすべてを同じスレッドで順番に実行してください。

実装では、実際にあなたが代わりに継続的にそれがKeptまたはBrokenPlannedから変更することは.status方法が待って呼び出すことでPromiseをポーリングし、だけにしてその結果を求めるならば、それはデッドロックのようなものになる可能性があり、ということでした場合。
これは、スペアスレッドがある場合、デフォルトのスケジューラがPromiseコードで作業を開始する理由の一部です。


jnthnのトーク“Parallelism, Concurrency, and Asynchrony in Perl 6”を見ることをおすすめします。
slides

+0

値を返す( 'await'を使うために)、値を正しい場所にコピーすると少し遅くなりました。また、コードは私のために読みにくいです。私は 'Thread'インターフェースを使用しようとしました。私は速度の増加を見ていないし、より低レベルです。 –

+0

@sid_com配列に配置すると、ループ処理の前に待機します。 @wait'がある 'for'ループに' await'を置いただけでは、すべてが完了する前に値の処理を開始するはずです。 –

4

この答えはMoarVMの状況の私の理解に適用される、芸術の状態は、JVMのバックエンド(またはJavaScriptのバックエンドFWIW)上にあるかわかりません。

  • 複数のスレッドからスカラーを安全に読み取ることができます。複数のスレッドからスカラーを変更
  • がセグメンテーション違反のために恐れることなく、行うことができますが、アップデートを見逃すことがあります。

$ perl6 -e 'my $i = 0; await do for ^10 { start { $i++ for ^10000 } }; say $i' 46785

同じことは配列のような、より複雑なデータ構造に適用されます(たとえば、不足しています値がプッシュされます)とハッシュ(欠落したキーが追加されます)。

このように、不足している更新が気にならない場合は、共有データ構造を複数のスレッドから変更すると機能するはずです。 @ Zoffix Znetと@raiphの示唆したように、アルゴリズムの設定を見直す必要があります。

-1





。他の答えは実装に関するあまりにも多くの仮定を作るようですが、どれも仕様によってテストされていません。

関連する問題