下記の意味がよくわかりません。
Using the TPL to create another thread to execute a CPU-bound operation while the originating thread has to
wait for it won’t help you with increasing performance.
下記のように訳してみましたが、よくわかりません。
オリジナルスレッドが待たなければならない間にCPU-BOUNDを実行する別スレッドを作成するためにTPLを
使用することは、パフォーマンスを上げることにならない。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
Using the TPL to create another thread to execute a CPU-bound operation while the originating thread has to
wait for it won’t help you with increasing performance.
その速度が CPU に依存するような処理を実行する別のスレッドを作り、元々のスレッドがそれを待たなくてはならないような場合、TPL をつかってもパフォーマンスは上がりません。
投稿2017/05/14 03:42
総合スコア28660
0
ベストアンサー
例えば重たい数式の計算だったり、メモリ上にロードされた全データのスキャンだったりみたいなのを非同期にラップしても、並列化した時精々最大でコア数分の軽量化にしかならない。それどころかスレッドをそれ以上作るとコンテキストスイッチ分動作速度が遅くなる。
また、メソッドの処理が極めて短い場合、1万の要素を並列化処理で4コアだから4スレッドたてて処理…ってやるにしても、その処理が1万回起動されるとスレッドの作成コストのせいで短くならなかったり。
(2500個の要素4つの配列に分けて実行すれば別だが、割り込みによって2500個同時にデータの処理が終わるわけではないのは想像がつくよね。つまりムズイってことだ!)
だから、IEnumerable<T>
を単純にAsParallel()
して、各メソッドに要素突っ込むぜ、コア全部使うぜ、これで最速だろ!なんて思っても、大体の場合早くならない。場合によっては遅くなる。
例えば、下記のコードはDoSomethingがCPU-BOUNDだと簡単には早くならない。
C#
1foreach (var item in items.AsParallel()) 2{ 3 DoSomething(item); 4}
CPUを消費する処理はそう単純に並列化によるパフォーマンス改善を受けられない。
非同期関数を作成する場合、もっとも効果が高いのはCPUを消費しない処理だ。
そういう、CPU-BOUNDではない処理ってなんだろうか。
それは例えば、データダウンロードとかのことだ。
データのダウンロードでは伝送コストの方がよっぽど高くて、ほとんどCPUは待機状態になる。
TCP/IPではデータ伝送のスループットがCPU計算よりずっと遅いからね。
そういったものは並列化に向いてる。
複数ファイル同時にダウンロードできるぐらいの性能がLANポートには十分あるし、シングルコアでも並列化することで高速化できる。
君のためにどうでもいいコードを書いてみた。
十分にCPU計算処理が重たい場合、コア数分は高速化する。
しかし、短いCPU計算の場合、速度は劣化する。
C#
1namespace ParallelSample 2{ 3 using System; 4 using System.Diagnostics; 5 using System.Linq; 6 using System.Threading.Tasks; 7 8 class Program 9 { 10 const int num = 100; 11 12 static void Main(string[] args) 13 { 14 if (args.Length != 1) return; 15 16 var start = long.Parse(args[0]); 17 18 var single = new Stopwatch(); 19 var result_s = new bool[num]; 20 single.Start(); 21 foreach (var i in Enumerable.Range(0, num)) 22 { 23 long value = start + i * 2; 24 result_s[i] = IsPrime(value); 25 } 26 single.Stop(); 27 28 Console.WriteLine($"シングルスレッド : {single.ElapsedMilliseconds}ms"); 29 30 var parallel = new Stopwatch(); 31 var result_p = new bool[num]; 32 parallel.Start(); 33 Parallel.ForEach(Enumerable.Range(0, num), i => 34 { 35 long value = start + i * 2; 36 result_p[i] = IsPrime(value); 37 }); 38 39 parallel.Stop(); 40 Console.WriteLine($"マルチスレッド : {parallel.ElapsedMilliseconds}ms"); 41 } 42 43 // 全ての値で割ってみて、素数か判定するのを原始的に行うメソッド 44 static bool IsPrime(long n) 45 { 46 for (long i = 2; i < n; i++) 47 { 48 if (n % i == 0) return false; 49 } 50 return true; 51 } 52 } 53}
結果は、i5-3470S@2.90GHzのPCで以下のようになった。
> ParallelSample 10001 シングルスレッド : 2ms マルチスレッド : 19ms > ParallelSample 100001 シングルスレッド : 11ms マルチスレッド : 21ms > ParallelSample 10000001 シングルスレッド : 595ms マルチスレッド : 207ms
原始的に素数判定を行っているため、素数の判定開始数値が大きくなると飛躍的にCPU処理時間が増える。
このため、計算量がスレッド開始のコストを上回る計算量になって初めてマルチスレッドはコア数分の時間短縮を受けられる。
しかし、通常私たちが使う計算式はそんなに長時間CPUを占有しないので、スレッド開始のコストが並列化のメリットを上回ってしまう。
例えば、重たい処理の一つにマップ探索アルゴリズムなどがあげられるが、これにしたって最適化されていれば単純に並列化しただけではパフォーマンス増加に繋がらない可能性は十分にあり得る。(メモリも沢山使うしね)
仮にI/Oバウンドな処理を行っていたとしても、並列数を引き上げ過ぎると「待機の確認」に時間がかかりすぎてしまい、速度は低下することもあるし、並列化は扱いが難しいものだ。
常に計測が必要ってことを覚えておいてもらえれば、とりあえずはいいんじゃないかな。
投稿2017/05/17 06:33
編集2017/05/17 07:34総合スコア1591
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/17 12:58
2017/05/17 13:01
0
こんにちは。
めっちゃ意訳すると、下記と思います。
CPUをぶん回すようなスレッドを実行し、その実行終了を元のスレッドが待つ時、TPLは役に立たない
シングル・コアのマシン、もしくは、複数のスレッドを同時に待てないようなライブラリの場合、成立すると思います。
TPLについて私は把握していませんが、TPLがそのような正直役に立たないライブラリなのか、その文の筆者がマルチ・コアのことを知らないのかのどちらかのように感じます。
あ、ごめんなさい。もう一つ、私の英語力不足でちゃんと読めていない可能性もあります。(落とし穴があるような英文ではないとは思いますが...)
投稿2017/05/14 10:06
総合スコア23272
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/14 13:05
2017/05/14 13:08