SHOEISHA iD

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

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

特集記事

PPLの並列アルゴリズム

  • X ポスト
  • このエントリーをはてなブックマークに追加

 PPL(Parallel Pattern Library)をご存じでしょうか。Visual C++ 10.0(Visual Studio 2010)以降で提供されているマイクロソフト製の並列プログラミングをサポートするライブラリです。PPLの並列アルゴリズムで素数探しプログラムのパフォーマンスを向上させるお話。

  • X ポスト
  • このエントリーをはてなブックマークに追加

素数探し

 とある正整数nがあって、2以上n未満のいかなる数もnを割り切ることができないとき、nは素数です。このルールに忠実に従うなら、nが素数であるか否かを判定する関数: is_prime()は以下のように定義できます。

list-1
bool is_prime(unsigned int n) {
  if ( n < 2U ) return false; // 0と1は素数じゃない
  // 2以上n未満の数 i が...
  for ( unsigned int i = 2U; i < n; ++i ) {
    // nを割り切るなら、nは素数じゃない
    if ( n % i == 0 ) return false;
  }
  return true;
}

 コレを使って5より大きな素数をすべて見つけるコードは:

list-2
// 2,3,5で割れない数は30の倍数+1,7,11...
unsigned int nth_prime_candidate(unsigned int x, unsigned int y) {
  static std::array<unsigned int,8> bias = { 1, 7, 11, 13, 17, 19, 23, 29 };
  return 30*x + bias[y];
}

inline unsigned int nth_prime_candidate(unsigned int n) {
  return nth_prime_candidate(n/8, n%8);
}

// 素数探し:見つけた素数はprimesに追加する
void prime_sequential(unsigned int limit, std::vector<unsigned int>& primes) {
    for (unsigned int i = 0; i < limit; ++i) {
        unsigned int n = nth_prime_candidate(i);
        if ( is_prime(n) ) primes.push_back(n);
    }
}

 処理時間を計測し、表示しましょうか。

list-3
inline std::chrono::milliseconds 
measure_exec(const std::function<void(unsigned int, std::vector<unsigned int>&)>& fun, 
             unsigned int limit, 
             std::vector<unsigned int>& result) {
  std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
  fun(limit, result);
  return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
}

int main() {
  const unsigned int LIMIT = 40000;
  vector<unsigned int> primes;
  vector<unsigned int>::size_type count;
  std::chrono::milliseconds durration;

  primes.clear();
  durration = measure_exec(&prime_sequential, LIMIT, primes);
  count = primes.size();
  cout << count << " primes found." << endl;
  cout << "----- sequential" << endl;
  cout << durration.count() << "[ms]" << endl;
}

 僕の愛機(CPU:i7-2600K)では、13845個の素数を見つけるのに5799[ms]かかりました。

PPLの並列アルゴリズム

 PPLでは"同時に(互いに干渉せずに)実行できる処理単位"を、タスク(task)と称しています。PPLの中ではCPUの力量に見合う数のスレッドを起こし、それらスレッドにユーザが定義した(複数の)タスクを投げ込んで処理を行います。そのからくりのおかげで、ユーザは明示的にスレッドを管理する必要がありません。加えて今回紹介する"parallel_"から始まる各種並列アルゴリズムはタスクの管理もユーザには任せず、「与えられた複数の処理を並列に実行し、全処理が完了するまで待つ(fork-join)」一連のパターンが関数内に封じ込められています。

 それでは、PPLが提供する並列アルゴリズムを1つずつ紹介しつつ、素数探しを高速化してみましょうか。

会員登録無料すると、続きをお読みいただけます

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

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

メールバックナンバー

次のページ
parallel_invoke(と同期オブジェクト/コンテナ)

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

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

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

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

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

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

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7632 2014/02/18 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング