SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

.NETでマンデルブロ集合を描く(後日談)
――Task Parallel Library/Parallel Patterns Libraryの利用

マルチスレッドでもっと高速化


TPLによる並行動作

 .NET Framework 4.0で新たに提供されるTPL(Task Parallel Library)は名前空間 System.Threading.Tasks にあり、コア・ライブラリ:mscorlib に含まれるので参照設定の追加の必要はありません。今回は最もシンプルな並列化メソッド Parallel.For を使います。

 計算コビト:MandelbrotPlotterにある計算ルーチンは次のようなコードです:

List-03:MandelbrotPlotter::Execute(C#)
public void Execute() {
  int w = paper_.GetWidth();
  int h = paper_.GetHeight();
  for ( int r = 0; r < w; ++r ) {
    for (int i = 0; i < h; ++i ) {
      paper_.SetPixel(r, i, Calculate(paper_.GetPoint(r, i)));
    }
  }
}

 ご覧の通り、二重のfor-loopになっています。外側のfor-loopを Parallel.For に置き換えます。Parallel.For の引数はループの始点と終点、そしてloop変数を引数とする(戻り値のない)delegate:System.Action<T>です。第3引数に与えるdelegateにラムダ式を使うと、上記コードは簡単に置き換えられます:

List-04:並行動作する MandelbrotPlotter::Execute(C#)
public void Execute() {
  int w = paper_.GetWidth();
  int h = paper_.GetHeight();
  System.Threading.Tasks.Parallel.For(0, w, // 始点と終点(0以上w未満)
        // inner-loopのラムダ式表現
        (int r) => {
          for ( int i = 0; i < h; ++i ) {
            paper_.SetPixel(r, i, Calculate(paper_.GetPoint(r, i)));
          }
        });
}

 たったこれだけ。Parallel.ForはCPUコア数その他の条件に応じて適切な数のスレッドを起こし、その中でdelegateを評価します。生成スレッド数の決定はライブラリが面倒みてくれます。

 添付のソリューションには C#, VB.NET, C++/CLI版を用意しています。僕のマシンはクロック2GHz強のAthlon dual-coreなんですけど、実行結果はC#版で500[ms]程度でした。こんなもんでしょうかね。

 quad-coreやHyper-Threadingによる仮想quad-core/octa-coreのリッチなCPUをお持ちの方はぜひお試しください。論理コア数に応じた速度向上が見込まれるはずです。コア数に応じてスケーラブルにパフォーマンスが上がるのは気持ちのいいものです。

おまけ:PPL(Parallel Patterns Library)によるnative-C++の並列化

 Visual C++ 10.0(2010)には.NET 4.0におけるTPLと同様のnativeなライブラリ:PPL(Parallel Patterns Library)が追加されています。せっかくだからこちらも使ってみました。

 PPLを使ったお試しコードを書いているとき、残念なことに気付きました。PPLを使うには#include <ppl.h>が必要なのですが、こいつを#includeしたコードを/clrオプション付けてC++/CLIとしてコンパイルすると:

fatal error C1189: #error :
ERROR: Concurrency Runtime is not supported when compiling /clr.

というエラー。PPLはC++/CLIでは使えないようです。

 ここまできてPPLを諦めるのも気持ちのいいものじゃありませんから、アプリケーションの構成を変更して無理やり(?)使ってみました。native-C++でなら問題なく

List-05:PPLによるMandelbrotPlotter::Execute(C++)
void MandelbrotPlotter::Execute() {
  int w = paper_->GetWidth();
  int h = paper_->GetHeight();
  Concurrency::parallel_for(0, w, // 0以上w未満に対し
    [&,this](int r) { // ラムダ式を並行評価する
      for ( int i = 0; i < h; ++i ) {
        paper_->SetPixel(r, i, Calculate(paper_->GetPoint(r,i),limit_));
      }
    });
  }
}

と書けるので、SectionPaperとMandelbrotPlotterをC++で実装し、native-DLLに仕立ててC++/CLIで実装したMailFormから利用します。添付ソリューション:Mandelbrot_CPPCLI_and_CPP をお試しください。

 nativeC++版の実行速度は.NETのなんと5倍:100[ms]を叩き出しました。nativeの面目躍如ってとこですか。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/4697 2009/12/28 16:27

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー