Python* プログラムの並列パフォーマンスを引き出そう

同カテゴリーの次の記事

Docker* 上に Ubuntu* 16.04 とインテル® Distribution for Python* の実行環境を構築する手順

この記事は、インテル® デベロッパー・ゾーンに公開されている「Unleash Parallel Performance of Python* Programs」の日本語参考訳です。


インテル® Distribution for Python* のリリースにより、Python* 開発者の皆さんにこれまでにない新しいモジュールを紹介できることを嬉しく思います。このモジュールは、2 つ以上のスレッド化されたライブラリーを利用して構成の容易性を高めることで、マルチスレッドの Python* プログラムにおいてさらなるパフォーマンスを引き出します。

利用可能なハードウェア・リソースよりもソフトウェア・スレッドが多い場合、非効率的なスレッドの割り当て (オーバーサブスクリプション) を回避し、プログラムを高速化します。

標準ライブラリーの ThreadPool のようなタスクプールや、Dask、Joblib (http://pythonhosted.org/joblib) のようなライブラリー (マルチスレッド・モードで使用) が、Numpy*/Scipy*/PyDAAL の計算負荷が高い関数を呼び出すタスクを実行する場合に、インテル® MKLインテル® TBB を利用して並列化することで、大幅なパフォーマンスの向上が得られます。

このモジュールは、インテル® TBB を利用して標準インターフェイスで Pool クラスを実装します。このクラスは、Python* の ThreadPool の代わりに使用できます。Monkey クラスで実装されるモンキーパッチ手法により、パフォーマンスを向上するためのソース変更は不要です。

実装例

すでにインテル® Distribution for Python* がインストールされていると仮定し、Python* コードの並列化を容易にする Dask ライブラリーをインストールします。

source <インテル® Distribution for Python* のパス>/bin/pythonvars.sh
conda install dask

入れ子の並列処理を実行し、処理時間を出力する bench.py という簡単なプログラムを作成します。

import dask, time
import dask.array as da

t0 = time.time()

x = da.random.random((10000, 10000), chunks=(4096, 4096))
x.dot(x.T).sum().compute()

print(time.time() - t0)

Dask は配列をチャンクに分割し、複数のスレッドを使用して並列に処理しますが、 各タスクには時間のかかる行列の乗算 (‘dot’) が含まれています。この処理は、インテル® MKL を利用することでマルチスレッド化し、高速化できます。その結果、インテル® TBB で効率良く処理できる入れ子の並列処理になります。

オリジナルのコードを実行するには、次のコマンドを使用します (ベースライン)。

python bench.py

パフォーマンスを向上するには、次のコマンドを使用します。

python -m TBB bench.py

これだけです。システム構成に応じて、この例では処理時間が 20% ~ 50% 短縮されます。バックグラウンド処理が実行されているシステムでは、さらなる向上が得られることがあります。

法務上の注意書き: インテル® TBB モジュールは、ブロック I/O 操作を効率良く処理できません。オペレーティング・システムをブロックしないタスクでのみ効果が得られます。このバージョンのインテル® TBB モジュールは試験的なもので、異なるユースケース向けに十分な最適化および検証が行われていません。

インテル® TBB モジュールの使用法については、ビルトインのドキュメント (pydoc TBB コマンドで表示) を参照してください。

このモジュールは、インテル® TBB 4.4 Update 5 のプレビュー機能としてソース提供されています。

皆様からのフィードバックをお待ちしております。特に、プロダクション/実稼働環境で使用を検討されている場合は、ぜひご連絡ください。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事