在主线程中使用 KeyboardException 中断 Python 中的线程

Jon*_*hen 5 python multithreading

我有几个类看起来或多或少是这样的:

import threading
import time

class Foo():
    def __init__(self, interval, callbacks):
        self.thread = threading.Thread(target=self.loop)
        self.interval = interval
        self.thread_stop = threading.Event()
        self.callbacks = callbacks

    def loop():
        while not self.thread_stop.is_set():
            #do some stuff...
            for callback in self.callbacks():
                callback()
            time.sleep(self.interval)

    def start(self):
        self.thread.start()

    def kill(self):
        self.thread_stop.set()
Run Code Online (Sandbox Code Playgroud)

我在我的主线程中使用的是这样的:

interval = someinterval
callbacks = [some callbacks]

f = Foo(interval, callbacks)

try:
    f.start()
except KeyboardInterrupt:
    f.kill()
    raise
Run Code Online (Sandbox Code Playgroud)

在所有回调完成后,但在循环重复之前,我想要一个 KeyboardInterrupt 来终止线程。目前它们被忽略,我不得不求助于终止程序运行的终端进程。

我从这篇文章中看到了使用 threading.Event 的想法,但看起来我做错了,这让这个项目的工作变得非常麻烦。

我不知道它是否相关,但是我从 Internet 传递访问数据的回调并大量使用重试装饰器来处理不可靠的连接。


编辑

在大家的帮助下,循环现在在 Foo 中看起来像这样:

    def thread_loop(self):
        while not self.thread_stop.is_set():
            # do some stuff
            # call the callbacks
            self.thread_stop.wait(self.interval)
Run Code Online (Sandbox Code Playgroud)

这是一种解决方案,尽管它并不理想。这段代码在PythonAnywhere 上运行,账户的价格是按 CPU 时间计算的。随着线程的不断唤醒和睡眠,我将不得不看看它在一天中使用了多少,但它至少解决了主要问题

Jon*_*hen 2

感谢@shx2 和@jazzpi 将拼图的两个独立部分拼凑在一起。

所以最终的代码是

import threading
import time

class Foo():
    def __init__(self, interval, callbacks):
        self.thread = threading.Thread(target=self.loop)
        self.interval = interval
        self.thread_stop = threading.Event()
        self.callbacks = callbacks

    def loop():
        while not self.thread_stop.is_set():
            #do some stuff...
            for callback in self.callbacks():
                callback()
            self.thread_stop.wait(self.interval)

    def start(self):
        self.thread.start()

    def kill(self):
        self.thread_stop.set()
Run Code Online (Sandbox Code Playgroud)

然后在主程序中

interval = someinterval
callbacks = [some, callbacks]
f = Foo(interval, callbacks)
f.start()
try:
    while True:
        time.sleep(0.1)
except KeyboardInterrupt:
    f.kill()
    raise
Run Code Online (Sandbox Code Playgroud)