Nic*_*mas 32 python multithreading concurrent.futures
我正在使用新concurrent.futures模块(也有一个Python 2 backport)来做一些简单的多线程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()
Run Code Online (Sandbox Code Playgroud)
当这个脚本运行时,似乎无法使用常规的Control-C键盘中断干净地杀死它.我在OS X上运行.
kill从命令行求助于杀死脚本.Control-C被忽略了.我在网上找到的大多数文档都讨论了如何用旧threading模块干净地杀死线程.这似乎都不适用于此.
concurrent.futures模块中提供的所有停止内容(如Executor.shutdown()和Future.cancel())的方法仅在Futures尚未启动或完成时才起作用,这在这种情况下毫无意义.我想立即打断未来.
我的用例很简单:当用户点击Control-C时,脚本应该像任何行为良好的脚本一样立即退出.这就是我想要的.
那么在使用时获得此行为的正确方法是concurrent.futures什么?
cdo*_*orn 18
这有点痛苦.本质上,您的工作线程必须在主线程退出之前完成.你不能退出,除非他们这样做.典型的解决方法是拥有一些全局状态,每个线程都可以检查以确定它们是否应该执行更多工作.
以下是解释原因的报价.实质上,如果在解释器执行时线程退出,则可能发生坏事.
这是一个有效的例子.请注意,Cc最多需要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
Run Code Online (Sandbox Code Playgroud)
小智 5
我遇到了这个问题,但我遇到的问题是许多期货(千分之十)将等待运行,只需按 Ctrl-C 就让它们等待,而不是实际退出。我concurrent.futures.wait用来运行一个进度循环,需要添加一个try ... except KeyboardInterrupt来处理取消未完成的期货。
POLL_INTERVAL = 5
with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool:
futures = [pool.submit(do_work, arg) for arg in large_set_to_do_work_over]
# next line returns instantly
done, not_done = concurrent.futures.wait(futures, timeout=0)
try:
while not_done:
# next line 'sleeps' this main thread, letting the thread pool run
freshly_done, not_done = concurrent.futures.wait(not_done, timeout=POLL_INTERVAL)
done |= freshly_done
# more polling stats calculated here and printed every POLL_INTERVAL seconds...
except KeyboardInterrupt:
# only futures that are not done will prevent exiting
for future in not_done:
# cancel() returns False if it's already done or currently running,
# and True if was able to cancel it; we don't need that return value
_ = future.cancel()
# wait for running futures that the above for loop couldn't cancel (note timeout)
_ = concurrent.futures.wait(not_done, timeout=None)
Run Code Online (Sandbox Code Playgroud)
如果您对准确跟踪已完成和未完成的内容(即不想要进度循环)不感兴趣,您可以将第一个等待调用(带有 的调用timeout=0)替换为not_done = futures并仍然保留while not_done:逻辑。
在for future in not_done:取消环大概可以表现不同基于该返回值(或写成理解),而是在等待完成或取消,是不是真的在等待期货-它立即返回。最后一个waitwithtimeout=None确保池的运行作业确实完成。
同样,这只有在do_work实际调用的情况下才能正常工作,最终在合理的时间内返回。这对我来说很好 - 事实上,我想确保如果do_work开始,它会运行到完成。如果do_work是“无限”,那么您将需要类似 cdosborn 的答案,该答案使用对所有线程可见的变量,向它们发出信号以停止自己。
| 归档时间: |
|
| 查看次数: |
13646 次 |
| 最近记录: |