2012-02-09 41 views
6

私は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上で)、これはすべてのジョブを提出した後、一貫ハングアップするようだ - と、これが提出されたジョブの数がより多い時はいつでも発生するようです労働者の数。私がProcessPoolExecutorThreadPoolExecutorに置き換えると、完璧に動作します。

調査する試みとして、私はそれぞれの将来に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の間違った値を表示します。だから、

は、誰もが説明することができます:python 3.2と iの「誤った」値が印刷されている理由を明らかにこのデッドロック

  • を固定電流のdevのバージョン間でProcessPoolExecutorに何が起こったのか

    EDIT:以下に指摘されているjukiewiczとして、もちろん印刷iが印刷されますコールバックが呼び出された時点の値で、私が考えていたことはわかりません... iの値を持つ呼び出し可能オブジェクトをその属性の1つとして渡すと、期待通りに機能します。

    EDIT:少し詳しい情報:すべてのコールバックが実行されるため、完了したことを知らせることができないexecutor.shutdownexecutor.__exit__が呼び出されているようです)のように見えます。これは現在のpython 3.3では完全に修正されているようですが、multiprocessingconcurrent.futuresには多くの変更が加えられているようですので、これを修正したのはわかりません。私は3.3を使用できません(それはnumpyのリリース版または開発版と互換性がないようです)。マルチプロセッシングとコンカレントパッケージを3.2のインストールにコピーしてみました。それでも、私が見る限りでは、ちょっと変わったようです - ProcessPoolExecutorは最新リリース版では完全に壊れていますが、誰も影響を受けていません。

  • +1

    2つ目は、プロセスが '99'を印刷するのは当然です。シンボル 'i'はグローバルコンテキストに束縛されており、新しいプロセスの作成にはコストがかかるので、何かを実行するまでには' i == 99'に​​なります。 – julkiewicz

    +1

    また、私はUbuntu 64ビット、Python 3.2.2を持っており、最初のコードスニペットはハングしません。 – julkiewicz

    +0

    @julkiewicz:それは非常に奇妙です。私はちょうど64ビットのScientific Linuxとpython 3.2.2を実行している別のマシンで試してみましたが、10のうち10試行で99を送信した後にストールしました。私は 'if __name__ == ' __main __ ''と聞いたことがありますが、これはWindows上のマルチプロセッシングに必要です。 – James

    答えて

    2

    コードを次のように変更し、両方の問題を解決しました。 callback関数はクロージャとして定義されていたため、毎回iの更新値が使用されます。デッドロックについては、すべてのタスクが完了する前にExecutorをシャットダウンする原因になる可能性があります。先物が完了するのを待つこともそれを解決する。

    from concurrent import futures 
    
    def test(i): 
        return i 
    
    def callback(f): 
        print('callback {}'.format(f.result())) 
    
    
    with futures.ProcessPoolExecutor(4) as executor: 
        fs = [] 
        for i in range(100): 
         print('submitting {}'.format(i)) 
         future = executor.submit(test, i) 
         future.add_done_callback(callback) 
         fs.append(future) 
    
        for _ in futures.as_completed(fs): pass 
    

    更新:ごめんなさい、あなたのアップデートを読んでいない、これはすでに解決されているようだ。

    関連する問題