小编典典

一旦期货开始,您如何杀死期货?

python

我正在使用新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上运行。

  • 在Python 2.7上,我必须kill从命令行求助以终止脚本。Control-C只是被忽略。
  • 在Python 3.4上,如果您按两次Control-C,它将起作用,但随后会丢弃许多奇怪的堆栈跟踪。

我在网上找到的大多数文档都谈到如何使用旧threading模块彻底杀死线程。这似乎都不适用于这里。

而且,concurrent.futures模块中提供的用于停止事物的所有方法(例如Executor.shutdown()Future.cancel())仅在期货尚未开始或尚未完成时才起作用,在这种情况下这是没有意义的。我想立即打断未来。

我的用例很简单:当用户点击Control-C时,该脚本应立即退出,就像任何行为良好的脚本一样。这就是我想要的。

那么使用时获得此行为的正确方法是concurrent.futures什么?


阅读 163

收藏
2020-12-20

共1个答案

小编典典

有点痛苦。本质上,您的工作线程必须在主线程退出之前完成。除非他们退出,否则您不能退出。典型的解决方法是具有一些全局状态,每个线程可以检查以确定它们是否应该做更多的工作。

这是解释原因的引文。本质上,如果在解释器执行操作时退出线程,则可能会发生不良情况。

这是一个工作示例。请注意,由于子线程的睡眠持续时间,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
2020-12-20