2016年02月12日

Prarallel構文を使ってタスクによる並列化を考える


先日、プログラム高速化の要望があったので、マルチコアCPUを使って、並列処理ができないか検討してみました。

C# で WinForm アプリケーションを書いていると、UI スレッド(フォアグラウンド)から、バックグラウンドスレッドに処理を任せても、バックグラウンドからは直接UIスレッドを触れないという問題に出くわしたりしますが、この別スレッドで動く仕組みを使うと、並列に処理を進めることができます。

このスレッドという仕組みは、同じメモリ空間にありながら、独立したスタックを持つことで並列に動くことができるわけですが、スレッドの生成、消去には、時間がかかります。そこで、あらかじめ用意したスレッド・プールに、小さな並列に動くプログラム断片を放り込んで、順番にスレッドとして動かす仕組みが作られました。(ここの詳しい説明は、スレッドプールとタスク がわかりやすいです。)

この小さなプログラム断片を Task と呼びますが、扱いにくいスレッドを抽象化して、C# から扱いやすくしたものと考えればいいと思います。こうしてスレッドプールをCPUのコア数程度用意すれば、Task を意識してプログラムを作るだけで並列度があげられそうです。従って、今後は、スレッドという用語に惑わされずに、Task で考えていくのがいいのでしょう。。。

この考えにマッチしているのが、Parallel 構文の For, ForEach, Invoke で、割と簡単に並列動作可能なプログラムが作れるようになります。これらの構文では、ラムダ式、関数呼び出しなども組み合わせられます。さらに、Async, Await という、非同期制御が書きやすい構文も追加されているので、これらを組み合わせれば、複数のCPUコアを効率よく使えそうです。いくつか実験的なプログラムを書いてみて気が付いたことですが、、

  • Task 同士が実行途中で共有変数を更新するようなロジックはなるべく考えない方がよい。(ロックが発生して、並列度が下がります。)

  • Task があまりに小さいと、Task 切り替えの時間が無視できないサイズになり、Parallel構文を使わない方が速くなってしまう。いろいろ試行錯誤してみましたが、ある程度以上のサイズにしないと並列化したメリットがでませんでした。

  • スレッドセーフなクラスの使用を優先する。

  • どこを並列化したらいいか考慮しながら設計する。


posted by 開発G at 11:33| Comment(0) | TrackBack(0) | Programming
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/173951461

この記事へのトラックバック