新しい _concurrent.futures
_ モジュール(Python 2バックポート)を使用して、単純なマルチスレッドI/Oを実行しています。理解に問題があります。このモジュールの使用を開始したタスクをきれいに強制終了する方法。
次のPython 2/3スクリプトを確認してください。これは、私が見ている動作を再現しています。
_#!/usr/bin/env python
from __future__ import print_function
import concurrent.futures
import time
def control_c_this():
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
future1 = executor.submit(wait_a_bit, name="Jack")
future2 = executor.submit(wait_a_bit, name="Jill")
for future in concurrent.futures.as_completed([future1, future2]):
future.result()
print("All done!")
def wait_a_bit(name):
print("{n} is waiting...".format(n=name))
time.sleep(100)
if __name__ == "__main__":
control_c_this()
_
このスクリプトの実行中は、通常のControl-Cキーボード割り込みを使用してきれいに殺すことは不可能に見えます。 OS Xで実行しています。
kill
に頼らなければなりません。Control-Cは無視されます。私が見つけたほとんどのドキュメントは、古いthreading
モジュールでスレッドをきれいに殺す方法についてのオンライントークを見つけました。ここでは当てはまらないようです。
そして、(Executor.shutdown()
やFuture.cancel()
などの)ものを停止する_concurrent.futures
_モジュール内で提供されるすべてのメソッドは、Futureがまだ開始していないか、完了している場合にのみ機能します。この場合は無意味です。 Futureをすぐに中断します。
私のユースケースは簡単です。ユーザーがControl-Cを押すと、スクリプトは正常に動作するスクリプトのようにすぐに終了します。それが私が望むすべてです。
それでは、_concurrent.futures
_を使用するときにこの動作を取得する適切な方法は何ですか?
ちょっと痛いです。基本的に、メインスレッドを終了するには、ワーカースレッドを終了する必要があります。終了しないと終了できません。典型的な回避策は、各スレッドがより多くの作業を行うべきかどうかを判断するためにチェックできるグローバルな状態にすることです。
これが quote の理由の説明です。本質的に、インタープリターが終了するときにスレッドが終了すると、悪いことが起こる可能性があります。
これが実際の例です。子スレッドのスリープ期間のため、C-cの伝播には最大で1秒かかることに注意してください。
#!/usr/bin/env python
from __future__ import print_function
import concurrent.futures
import time
import sys
quit = False
def wait_a_bit(name):
while not quit:
print("{n} is doing work...".format(n=name))
time.sleep(1)
def setup():
executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
future1 = executor.submit(wait_a_bit, "Jack")
future2 = executor.submit(wait_a_bit, "Jill")
# main thread must be doing "work" to be able to catch a Ctrl+C
# http://www.luke.maurits.id.au/blog/post/threads-and-signals-in-python.html
while (not (future1.done() and future2.done())):
time.sleep(1)
if __name__ == "__main__":
try:
setup()
except KeyboardInterrupt:
quit = True