首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >一旦Futures启动,你是如何杀死它们的?

一旦Futures启动,你是如何杀死它们的?
EN

Stack Overflow用户
提问于 2015-03-21 07:42:07
回答 3查看 34K关注 0票数 57

我正在使用新的concurrent.futures模块(它也有一个Python2后端口)来做一些简单的多线程I/O。我在理解如何干净利落地杀死开始使用这个模块的任务时遇到了麻烦。

看看下面的Python 2/3脚本,它重现了我看到的行为:

代码语言:javascript
复制
#!/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上运行。

  • On Python2.7我必须从命令行使用kill来终止脚本。Control C被忽略了。Python3.4上的
  • ,如果你点击两次Control C就可以工作,但之后会有很多奇怪的堆栈跟踪被丢弃。

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

concurrent.futures模块中提供的所有方法(如Executor.shutdown()Future.cancel())仅在Futures尚未启动或完成时才起作用,在这种情况下,这是没有意义的。我想立即中断未来。

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

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-03-24 23:58:33

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

以下是解释原因的quote。从本质上讲,如果线程在解释器退出时退出,可能会发生不好的事情。

下面是一个有效的示例。请注意,C-c传播最多需要1秒,因为子线程的睡眠持续时间较长。

代码语言:javascript
复制
#!/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
票数 38
EN

Stack Overflow用户

发布于 2020-08-20 05:36:14

我遇到了这个问题,但我遇到的问题是,许多期货(成千上万的10个)将等待运行,只需按Ctrl-C组合键,他们就会等待,而不是真正退出。我使用concurrent.futures.wait运行进度循环,需要添加一个try ... except KeyboardInterrupt来处理取消未完成的未来。

代码语言:javascript
复制
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)

如果你对准确跟踪哪些已经完成,哪些没有完成不感兴趣(也就是不想要一个进度循环),你可以用not_done = futures替换第一个等待调用(带有timeout=0的那个),并且仍然保留while not_done:逻辑。

for future in not_done: cancel循环可能会根据返回值不同而表现不同(或者写成一种理解),但是等待完成或取消的期货并不是真正等待-它会立即返回。带有timeout=None的最后一个wait确保池中正在运行的作业真正完成。

同样,只有当被调用的do_work最终在一段合理的时间内返回时,它才能正常工作。这对我来说很好--事实上,我希望确保如果do_work启动,它会运行到完成。如果do_work是“永无止境的”,那么你需要类似于cdosborn的answer,它使用一个对所有线程都可见的变量,向它们发出停止自身的信号。

票数 5
EN

Stack Overflow用户

发布于 2021-12-21 22:40:11

聚会迟到了,但我也遇到了同样的问题。

我想立即终止我的程序,我不关心发生了什么。除了Linux所能做的之外,我不需要干净的关机。

我发现用os.kill(os.getpid(), 9)替换KeyboardInterrupt异常处理程序中的geitda代码会在第一个^C代码之后立即退出。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29177490

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档