注: この回答は、私が最終的に問題を解決した方法ですが、プロセス間で激しい転送を行っている場合は、Velimir の回答がより適しています。私は持っていないので、必要ありませんでしたsharedmem
。
どのように私はそれをやった
NumPy 配列の酸洗いに費やした時間はごくわずかであり、心配しすぎていたことがわかりました。基本的に、私がやっていることはMapReduce操作なので、これをやっています:
まず、Unix システムでは、プロセスを生成する前にインスタンス化したオブジェクトは、必要に応じてプロセスのコンテキストに存在 (およびコピー) されます。これはコピー オン ライト(COW) と呼ばれ、カーネルによって自動的に処理されるため、非常に高速です (そして、私の目的には間違いなく十分に高速です)。ドキュメントには、ピクルス化が必要なオブジェクトに関する多くの警告が含まれていましたが、ここでは、入力にはまったく必要ありませんでした。
次に、各プロセス内から、ディスクからイメージをロードすることになりました。各画像は独自のワーカーによって個別に処理 (マップ) されるため、大量のデータのバッチをロックしたり送信したりすることはなく、パフォーマンスが低下することもありません。
各ワーカーは、処理するマップされた画像に対して独自の削減を行い、結果をQueue
. リダクション関数から得られる通常の出力は、5000 x 5000 ピクセルに近いサイズの 4 または 5 チャネルの 32 ビット float 画像です (それぞれ約 300 または 400 MB のメモリ)。
最後に、各プロセスから中間リダクション出力を取得し、メイン プロセスで最終リダクションを行います。
数百メガバイトを消費している場合でも、キューを使用して画像を転送するときにパフォーマンスの低下は見られません。私はそれを 6 コアのワークステーションで実行しました (HyperThreading を使用しているため、OS は 12 の論理コアを認識します) multiprocessing
。6 コアを使用すると、使用しない場合よりも 6 倍高速multiprocessing
でした。
(不思議なことに、12 個のコア全体で実行しても 6 より速くはなりませんでしたが、ハイパースレッディングの制限に関係していると思われます。)
プロファイリング
もう 1 つの懸念事項は、発生しているオーバーヘッドのプロファイリングと定量化multiprocessing
でした。私が学んだいくつかの便利なテクニックを次に示します。
組み込みの (少なくとも私のシェルの)time
コマンドと比較して、time
実行可能ファイル( /usr/bin/time
Ubuntu の) は、平均 RSS、コンテキスト スイッチ、平均 %CPU などを含む、はるかに多くの情報を提供します。私ができるすべてを得る:
$ /usr/bin/time -v python test.py
プロファイリング (IPython を使用%run -p
または%prun
IPython で) は、メイン プロセスのみをプロファイリングします。この回答のように、生成したすべてのプロセスにフックcProfile
して、個々のプロファイルをディスクに保存できます。
DEBUG_PROFILE
これをオン/オフに切り替える何らかのフラグを追加することをお勧めします。いつ必要になるかわかりません。
最後になりましたが、次のような実行中の Python プロセスの 1 つにアタッチすることにより、syscall プロファイルから多かれ少なかれ有用な情報を取得できます (主に、OS がプロセス間で大量のデータを転送するのに時間がかかっていないかどうかを確認するため)。
$ sudo strace -c -p <python-process-id>