yohhoyの日記

技術的メモをしていきたい日記

Boost.Asioでお手軽並列ライブラリを実装

Boost.Asioを使って、スレッドプールを利用した簡単な並列アルゴリズムを実装してみた。名前は適当にTiny Parallel Library(むしろ"Toy"の方が似合う気がする)。

概要

実装した並列アルゴリズムは下記3つのみで、インタフェースはIntel TBBおよびMicrosoft PPL互換としている。

  • parallel_for_each
  • parallel_for
  • parallel_invoke

既定動作では 論理プロセッサ数-1 のワーカスレッドプールを生成し、ワーカスレッド数=論理プロセッサ数として並列アルゴリズムを実行する*1。並列ループparalle_for_each, parallel_forは、入力範囲を論理プロセッサ数で単純にブロックへ分割して並行処理を行う。なお、並列アルゴリズム入れ子構造としても正常に動作する*2。(例:parallel_invokeで呼び出した関数内でparallel_forを行うなど。)

注意:ライブラリ実装では例外について考慮していない!!(ToDo:Boost.Asioの例外処理について調べる)

ライブラリコード


メモ

  • Boost.Atomicが欲しかった。Boost.Interprocess内部実装にatomic整数があったためこちらで代用。
  • impl::waiter::~waiter()で「自スレッドで処理可能なタスクが存在しない」かつ「他スレッドでのタスク完了を待機中」の場合、waiter::counter_変数への激しいポーリング処理が発生する。この状況が生じるのは「並列アルゴリズムを組み合わせた」または「並列化したタスクの処理時間が不均一」のとき。
    • 単純にブロッキング型待機に替えるとCPUリソース浪費を避けられるが、並列アルゴリズムを組み合わせた時にデッドロックが生じる。現状の変数ポーリング+poll_one()なら少なくとも進行保障がある。
  • 単純な利用ケースに限ればIntel TBBに近い性能がでるが、並列アルゴリズムを組み合わせるような複雑なケースでは明らかに劣る。
  • 並列アルゴリズム入れ子にする(parallel_invokeを用いる関数の再帰呼び出しなど)とコールスタック消費が激しい。この観点ではIntel TBBが明らかに優れていた。

*1:並列アルゴリズムを呼び出したスレッド自身+スレッドプールのスレッド群が論理プロセッサ数と等しい。

*2:あくまで「正常動作すること」を保証するのみ。実行効率については何も考慮していない。