質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

2527閲覧

順序性が求められる計算にParallel.Forを使って排他制御を行わずに正しい計算結果を算出できるのか

papi1204

総合スコア8

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2019/08/07 04:07

編集2019/08/07 04:48

先日Parallel.Forについて質問したのですが、再度質問させていただきます。
順序性が求められる計算にParallel.Forを突っ込んで、
正しい計算結果を出すには排他制御をするしかないのでしょうか?

内容によって出来るかどうかは変わってくるかもしれないですが
とりあえずは下記コードを参考に教えていただけないでしょうか。

C#

1private void Button2_Click(object sender, EventArgs e) 2 { 3 int i = 1; 4 int j = 2; 5 Int64 ansewr = 0; 6 var sw = new System.Diagnostics.Stopwatch(); 7 sw.Start(); 8 9 Parallel.For(0, 10, y => 10 { 11 for (int x = 0; x < 10; x++) 12 { 13 ansewr += i * j + x; 14 } 15 }); 16 17 sw.Stop(); 18 textBox1.Text = ansewr.ToString(); 19 label2.Text = sw.Elapsed.ToString(); 20 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2019/08/07 04:08

普通に for を使えばいいのでは?
papi1204

2019/08/07 04:33

Parallel.forで処理できるかどうかを知りたいのです…
fana

2019/08/07 04:34

> とりあえずは下記コードを参考に 並列以前に500回繰り返す意味がない処理に見えるので,順序性の話との関連性がわからないです.
ozwk

2019/08/07 04:34

これParallel.Forの処理順で計算結果変わります?
papi1204

2019/08/07 04:45

申し訳ありません。。計算式を間違えてました… 500回回してたのは処理時間を計測で時間を掛かるのを試しており、修正忘れです…
papi1204

2019/08/07 04:47

なんなら二重ループでもいいですよね。。修正します。
Zuishin

2019/08/07 04:51

どっちにしろ順序関係ないように見えます。この処理なら並列に計算した結果を終わった順に足していけばいいだけだと思います。 例えばフィボナッチ数の計算なら順序関係ありますが、これを非同期で行う意味はありません。 想定するケースがよくわかりません。
papi1204

2019/08/07 04:59

自分が順序性を間違えて理解してました… お恥ずかしい限りです。。申し訳ありません…
YAmaGNZ

2019/08/07 05:17

私が前回の質問で「順序性」という言葉を使ったからですね。 前回は「似たような記述のint型、計算処理プログラムを作成するも」とあるだけで、ソースが無かったために、ループ順番が関係する処理だったのでは?思ったため「順序性」という言葉を使いました。
papi1204

2019/08/07 06:06

前回ソースを上げず、勝手に思い込んだ自分が悪いので気になさらないでください。 そもそも順序性という漢字を見ればある程度想像付くはずなのに、意味の分からない思い込みをしてた自分が悪いです。
coco_bauer

2019/08/07 06:42

質問のコードは、計算の順序性を含まないように思われます。変数xは利用されていないし、変数ansewrは代入されるだけで、結局最後に代入された値が残るだけ。Parallel.For を使う必要があるコード例はないのでしょうか?
guest

回答1

0

ベストアンサー

こんにちは。

質問のコード例からは「順序性」がなんなのか全く読み取れないため、適当に補完して回答します。

Parallel.For は各ループ処理が最初に与えられるカウンタによって隔離されたコンテキストを持つものと看做せるため、「各ループ処理毎に、別のループの結果に影響されず、また別のループの条件に影響しない」ようにすることで排他制御を不要にすることができます。
具体的には、以下の条件を満たすようにコードを記述します。

  • For 内で、他のループによって書き換えられる変数を読み取りしない
  • For 内で、他のループによって参照される変数に書き込みをしない
  • For 内で、読み取る毎に値が変化する可能性がある変数にアクセスしない

質問のコードにおいては、ij をループ内で読む場合、これらがループ中で値が変更されないことを保証していれば良いです。
answer の場合、各ループが書き込みを行っているため、これはスレッドセーフになりません。各ループ毎に「異なる answer」に書き込むことでこれを解決する手段があります。

以上の条件を基に適当に書き換えをしてみたのが以下です。

csharp

1private void Button2_Click(object sender, EventArgs e) 2{ 3 var sw = new System.Diagnostics.Stopwatch(); 4 sw.Start(); 5 6 var answer = new long[500]; // `answer` はループ毎に異なる領域を持たせる 7 8 Parallel.For(0, 500, y => // 各ループ処理は `y` について独立である 9 { 10 for (int x = 0; x < 500; x++) 11 { 12 for (int c = 0; c < 500; c++) 13 { 14 answer[y] += x + c + y; // `y` で区切られた領域にのみアクセスする 15 } 16 } 17 }); 18 19 sw.Stop(); 20}

answer を配列にしているのがキモで、配列は同時アクセスを許容するので、ループ毎に独立した領域を扱うようにすることでスレッドセーフにできます。
i j については質問から意図が読み取れなかったため無視しています。

その他、Parallel を使う以上は、処理中でスレッドアンセーフな API を一切利用しないことは徹底していないといけませんが、これは大前提なのであえて説明するまでもないですね。

投稿2019/08/07 04:49

tamoto

総合スコア4304

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

papi1204

2019/08/07 05:01

ご丁寧にありがとうございます! 自分が順序性の意味を履き違えてました…お恥ずかしい限りです…
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問