未来一旦开始,你怎么杀了他们?

2024-05-20 08:45:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用新的^{}模块(它也有一个Python 2后台端口)来执行一些简单的多线程I/O操作。我很难理解如何干净地终止使用此模块开始的任务。

查看下面的Python2/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键盘中断似乎不可能完全终止。我在OSX上运行

  • 在Python 2.7上,我必须从命令行中使用kill来终止脚本。Control-C被忽略了。
  • 在Python3.4中,如果您两次点击Control-C,它就会工作,但随后会转储许多奇怪的堆栈跟踪。

我在网上找到的大多数文档都讨论了如何使用旧的threading模块干净地杀死线程。这些似乎都不适用于这里。

而在concurrent.futures模块中提供的用于停止数据的所有方法(比如Executor.shutdown()Future.cancel())只在未来尚未开始或完成时才起作用,这在本例中是没有意义的。我想马上打断你的未来。

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

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


Tags: 模块nameimport脚本timedefbitfuture
1条回答
网友
1楼 · 发布于 2024-05-20 08:45:44

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

这是解释原因的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

相关问题 更多 >