並列実行時にCPUがどのように動いているのか、今回はその挙動をもう少し視覚的に確認していきます。
CPU使用率を確認
下記のサンプルコードはfor文とParallel.For文の中で長いループ処理をしているだけの簡単なものです。それぞれの経過時間の測定も行っています。このときのCPU使用率をタスクマネージャーで確認します。
using System; using System.Diagnostics; using System.Threading.Tasks; namespace Sample03_BehaviorResearch { class Program { static void Main() { Console.ReadLine(); //--- しばらく待ってから何か押しましょう var stopwatch = Stopwatch.StartNew(); for (int i = 0; i < 50000; i++) for (int j = 0; j < 50000; j++); stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed.TotalSeconds.ToString("通常 : #.#####[s]")); Console.ReadLine(); //--- しばらく待ってから何か押しましょう stopwatch.Restart(); Parallel.For(0, 50000, i => { for (int j = 0; j < 50000; j++); }); stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed.TotalSeconds.ToString("並列 : #.#####[s]")); } } } //----- 結果 (例) /* 通常 : 8.27524[s] 並列 : 1.87966[s] */
通常のfor文 | Parallel.For文 |
---|---|
![]() |
![]() |
上記のサンプルを実行してタスクマネージャーでCPUにかかる負荷を見てみると、Parallel.For文の方がすべてのCPUを利用して稼働していることが確認できます。実行時間も4分の1以下になっています。このように、.NET Framework側で実行環境にあるCPUに対して自動的かつ最適に処理を振り分けてくれます。
呼び出し元スレッドのブロック
もう一点、重要なところがあります。Parallel.For/ForEachとも呼び出し元のスレッドをブロックするということです。上記の例からも、Parallel.For内で生成されるすべてのスレッドの終了を待機したのち、経過時間が表示されていることが確認できます。コレクションの各要素に対して並列に処理が実行されることと呼び出し元スレッドに対して非同期に処理が行われることは別ですので、十分注意してください。
次回予告
Parallel.For/ForEachには多数のオーバーロードがあります。これらを利用することで、並列処理を停止したり中断したりすることができます。次回はその辺について触れてみます。