1

この件に関して、特に StackOverflow について尋ねられた大量の質問から得た警告と混乱した感情にもかかわらず、私は恥ずかしいほどに並列化された問題の単純なバージョンを並列化しました (基本的に、リストのread-image-do-stuff-return多くの画像)、計算ごとに結果の NumPy 配列を返し、callbackパラメーターを介してグローバル NumPy 配列を更新し、すぐに8 コア マシンで5 倍のスピードアップを達成しました。

各コールバック呼び出しでロックが必要なため、x8 を取得できなかった可能性がありますが、得られたものは心強いものです。

これを改善できるかどうか、またはこれが良い結果かどうかを調べようとしています。質問:

  • 返された NumPy 配列がピクルされたと思いますか?
  • 基礎となる NumPy バッファはコピーされたか、参照によって渡されましたか?
  • ボトルネックが何であるかを知るにはどうすればよいですか? 特に便利なテクニックはありますか?
  • それを改善できますか、それともそのような場合、そのような改善はかなり一般的ですか?
4

2 に答える 2

0

sharedmemモジュールを使用して、複数のプロセス間で大きな NumPy 配列を (もちろん参照により) 共有することに成功しました: https://bitbucket.org/cleemesser/numpy-sharedmem。基本的に、NumPy 配列を渡すときに通常発生する酸洗いを抑制します。あなたがしなければならないのは、代わりに:

import numpy as np
foo = np.empty(1000000)

これを行う:

import sharedmem
foo = sharedmem.empty(1000000)

foo次のように、あるプロセスから別のプロセスに渡します。

q = multiprocessing.Queue()
...
q.put(foo)

ただし、このモジュールには、不正なプログラムの終了時にメモリ リークが発生する可能性が知られていることに注意してください。 -ピクルス-コピー

お役に立てれば。このモジュールを使用して、マルチコア マシンでのライブ画像処理を高速化します (私のプロジェクトはhttps://github.com/vmlaker/sherlockです)。

于 2013-05-20T17:43:53.800 に答える
0

注: この回答は、私が最終的に問題を解決した方法ですが、プロセス間で激しい転送を行っている場合は、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/timeUbuntu の) は、平均 RSS、コンテキスト スイッチ、平均 %CPU などを含む、はるかに多くの情報を提供します。私ができるすべてを得る:

     $ /usr/bin/time -v python test.py
    
  • プロファイリング (IPython を使用%run -pまたは%prunIPython で) は、メイン プロセスのみをプロファイリングします。この回答のように、生成したすべてのプロセスにフックcProfileして、個々のプロファイルをディスクに保存できます。

    DEBUG_PROFILEこれをオン/オフに切り替える何らかのフラグを追加することをお勧めします。いつ必要になるかわかりません。

  • 最後になりましたが、次のような実行中の Python プロセスの 1 つにアタッチすることにより、syscall プロファイルから多かれ少なかれ有用な情報を取得できます (主に、OS がプロセス間で大量のデータを転送するのに時間がかかっていないかどうかを確認するため)。

     $ sudo strace -c -p <python-process-id>
    
于 2013-05-21T19:03:37.987 に答える