51

複数のファイルでPythonコードを並行して実行しようとしています。構成は基本的に次のとおりです。

def process_file(filename, foo, bar, baz=biz):
    # do stuff that may fail and cause exception

if __name__ == '__main__':
    # setup code setting parameters foo, bar, and biz

    psize = multiprocessing.cpu_count()*2
    pool = multiprocessing.Pool(processes=psize)

    map(lambda x: pool.apply_async(process_file, (x, foo, bar), dict(baz=biz)), sys.argv[1:])
    pool.close()
    pool.join()

私は以前にpool.mapを使用して同様のことを行いましたが、これはうまく機能しましたが、pool.mapでは追加の引数を渡すことができない(およびラムダを使用して)ため、ここでは使用できないようです。ラムダをマーシャリングできないため、機能しません)。

だから今私はapply_async()を直接使って物事を動かそうとしています。私の問題は、コードがハングして終了しないように見えることです。いくつかのファイルは例外で失敗しますが、なぜ結合が失敗/ハングするのかわかりません。興味深いことに、例外を除いてどのファイルも失敗しない場合、ファイルは正常に終了します。

私は何が欠けていますか?

編集:関数(したがってワーカー)が失敗すると、次の例外が表示されます:

Exception in thread Thread-3:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 505, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 376, in _handle_results
    task = get()
TypeError: ('__init__() takes at least 3 arguments (1 given)', <class 'subprocess.CalledProcessError'>, ())

これらの1つでも表示された場合、プロセスの親プロセスは永久にハングし、子を刈り取って終了することはありません。

4

3 に答える 3

56

私自身の質問に答えて申し訳ありませんが、少なくとも回避策を見つけたので、他の誰かが同様の問題を抱えている場合に備えて、ここに投稿したいと思います。私はそこにもっと良い答えを受け入れます。

問題の根本はhttp://bugs.python.org/issue9400だと思います。これは私に2つのことを教えてくれます:

  • 私は頭がおかしいわけではありません、私がやろうとしていることは本当にうまくいくはずです
  • 少なくともpython2では、「例外」を親プロセスに戻すことは不可能ではないにしても非常に困難です。単純なものは機能しますが、他の多くは機能しません。

私の場合、ワーカー関数はsegfaultingであるサブプロセスを起動していました。これにより、ピクルス化できないCalledProcessError例外が返されました。何らかの理由で、これにより、親のプールオブジェクトが昼食に出て、join()の呼び出しから戻らないようになります。

私の特定のケースでは、例外が何であったかは気にしません。せいぜいログに記録して続けたいと思います。これを行うには、トップワーカー関数をtry/except句でラップするだけです。ワーカーが例外をスローした場合、親プロセスに戻ろうとする前にキャッチされてログに記録されます。その後、ワーカープロセスは例外を送信しようとしなくなったため、通常どおり終了します。下記参照:

def process_file_wrapped(filenamen, foo, bar, baz=biz):
    try:
        process_file(filename, foo, bar, baz=biz)
    except:
        print('%s: %s' % (filename, traceback.format_exc()))

次に、元のマップ関数の代わりに、最初のマップ関数でprocess_file_wrapped()を呼び出します。これで、私のコードは意図したとおりに機能します。

于 2013-03-09T21:51:48.867 に答える
5

オブジェクトをピクルスにする必要がある場合は、実際にはのfunctools.partial代わりにインスタンスを使用できます。オブジェクトは、Python 2.7以降(およびPython 3)でピクルス化できます。lambdapartial

pool.map(functools.partial(process_file, x, foo, bar, baz=biz), sys.argv[1:])
于 2013-03-10T02:07:02.680 に答える
3

pool.map価値があるのは、ハングしたときに同様のバグ(同じではない)があったことです。私のユースケースでは、pool.terminateを使用してそれを解決することができました(変更する前に、自分のユースケースでも同様に機能することを確認してください)。

呼び出す前にpool.mapを使用したので、ドキュメントterminateからすべてが終了したことがわかります。

map()組み込み関数と同等の並列機能(ただし、反復可能な引数は1つだけサポートします)。結果の準備ができるまでブロックします。

それがあなたのユースケースであるなら、これはそれをパッチする方法かもしれません。

于 2014-12-16T18:01:34.703 に答える