私はconcurrent.futures.ProcessPoolExecutor
を使っていくつかのコードを並列化しようとしていましたが、ThreadPoolExecutor
では発生しない奇妙なデッドロックが続いています。最小限の例:pythonの3.2.2で同時コードのデッドロック
from concurrent import futures
def test():
pass
with futures.ProcessPoolExecutor(4) as executor:
for i in range(100):
print('submitting {}'.format(i))
executor.submit(test)
(64ビットのUbuntu上で)、これはすべてのジョブを提出した後、一貫ハングアップするようだ - と、これが提出されたジョブの数がより多い時はいつでも発生するようです労働者の数。私がProcessPoolExecutor
をThreadPoolExecutor
に置き換えると、完璧に動作します。
調査する試みとして、私はそれぞれの将来にi
の値を印刷するためのコールバックを与えた:
from concurrent import futures
def test():
pass
with futures.ProcessPoolExecutor(4) as executor:
for i in range(100):
print('submitting {}'.format(i))
future = executor.submit(test)
def callback(f):
print('callback {}'.format(i))
future.add_done_callback(callback)
これはちょうど、さらに私を混同 - callback
プリントアウトi
の値は、値であり、それが定義されたときではなく、呼び出された時(callback 0
は表示されませんが、callback 99
がたくさんあります)。再び、ThreadPoolExecutor
は期待値を表示します。
これがバグかもしれない場合は、私は最近のpythonの開発版を試しました。さて、コードは少なくとも終了するようですが、私はまだi
の間違った値を表示します。だから、
i
の「誤った」値が印刷されている理由を明らかにこのデッドロック
を固定電流のdevのバージョン間でProcessPoolExecutor
に何が起こったのか
EDIT:以下に指摘されているjukiewiczとして、もちろん印刷i
が印刷されますコールバックが呼び出された時点の値で、私が考えていたことはわかりません... i
の値を持つ呼び出し可能オブジェクトをその属性の1つとして渡すと、期待通りに機能します。
EDIT:少し詳しい情報:すべてのコールバックが実行されるため、完了したことを知らせることができないexecutor.shutdown
(executor.__exit__
が呼び出されているようです)のように見えます。これは現在のpython 3.3では完全に修正されているようですが、multiprocessing
とconcurrent.futures
には多くの変更が加えられているようですので、これを修正したのはわかりません。私は3.3を使用できません(それはnumpyのリリース版または開発版と互換性がないようです)。マルチプロセッシングとコンカレントパッケージを3.2のインストールにコピーしてみました。それでも、私が見る限りでは、ちょっと変わったようです - ProcessPoolExecutor
は最新リリース版では完全に壊れていますが、誰も影響を受けていません。
2つ目は、プロセスが '99'を印刷するのは当然です。シンボル 'i'はグローバルコンテキストに束縛されており、新しいプロセスの作成にはコストがかかるので、何かを実行するまでには' i == 99'になります。 – julkiewicz
また、私はUbuntu 64ビット、Python 3.2.2を持っており、最初のコードスニペットはハングしません。 – julkiewicz
@julkiewicz:それは非常に奇妙です。私はちょうど64ビットのScientific Linuxとpython 3.2.2を実行している別のマシンで試してみましたが、10のうち10試行で99を送信した後にストールしました。私は 'if __name__ == ' __main __ ''と聞いたことがありますが、これはWindows上のマルチプロセッシングに必要です。 – James