を使用していくつかのコードを並列化しようとしましたがconcurrent.futures.ProcessPoolExecutor
、 では発生しない奇妙なデッドロックが発生し続けていますThreadPoolExecutor
。最小限の例:
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)
Python 3.2.2 (64 ビット Ubuntu 上) では、これはすべてのジョブを送信した後に一貫してハングしているように見えます。これは、送信されたジョブの数がワーカーの数よりも多い場合に発生するようです。私が交換ProcessPoolExecutor
した場合、ThreadPoolExecutor
それは問題なく動作します。
調査の試みとして、各 Future に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)
これは私をさらに混乱させました-i
出力された bycallback
の値は、定義されたときではなく、呼び出されたときの値です(したがって、表示されませんcallback 0
が、多くのcallback 99
s が得られます)。繰り返しThreadPoolExecutor
ますが、期待値を出力します。
これはバグではないかと思い、最近開発された Python のバージョンを試してみました。これで、コードは少なくとも終了したように見えますが、それでも間違った値がi
出力されます。
誰でも説明できます:
ProcessPoolExecutor
Python 3.2 と、このデッドロックを明らかに修正した現在の開発バージョンの間で何が起こったのかの「間違った」値
i
が表示される理由
編集: jukiewicz が以下で指摘したように、もちろん、印刷i
するとコールバックが呼び出されたときに値が印刷されます。何を考えていたのかわかりません...i
属性の 1 つとして値を持つ呼び出し可能なオブジェクトを渡す場合、期待どおりに動作します。
EDIT:もう少し情報:すべてのコールバックが実行されるため、プロセスが完了したことを伝えることができないexecutor.shutdown
(によって呼び出される)ようです。これは現在の python 3.3 で完全に修正されたようですが、とexecutor.__exit__
に多くの変更があったようです。そのため、何が修正されたのかわかりません。私は 3.3 を使用できないので (numpy のリリース バージョンまたは開発バージョンと互換性がないようです)、そのマルチプロセッシング パッケージとコンカレント パッケージを 3.2 インストールに単純にコピーしてみましたが、問題なく動作しているようです。それでも、私が見る限り、最新のリリース バージョンでは完全に壊れているのに、他の誰も影響を受けていないというのは少し奇妙に思えます。multiprocessing
concurrent.futures
ProcessPoolExecutor