我有一些看起来或多或少的类:
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()
我在主线程中使用的是这样的:
interval = someinterval
callbacks = [some callbacks]
f = Foo(interval, callbacks)
try:
f.start()
except KeyboardInterrupt:
f.kill()
raise
我希望KeyboardInterrupt在所有回调完成后但在循环重复之前终止线程。目前它们被忽略了,我不得不求助于杀死程序运行的终端进程。
我看到了使用来自this post的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)
这是种解决方案,虽然它并不理想。此代码在PythonAnywhere上运行,帐户的价格是CPU时间。我将不得不看到它在一天的过程中使用多少线程不断的醒来和睡眠,但它至少解决了主要问题
答案 0 :(得分:3)
我认为您的问题是try-except
- f.start()
周围有一个阻止,但会立即返回,因此您不会在线程后抓住KeyboardInterrupt
s开始了。
您可以尝试在程序底部添加while循环,如下所示:
f.start()
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
f.kill()
raise
这不是最优雅的解决方案,但它应该有效。
答案 1 :(得分:1)
@ jazzpi的回答正确地解决了您在主线程中遇到的问题。
对于线索循环中的sleep
,您只需拨打sleep
即可将呼叫替换为self.thread_stop.wait(self.interval)
。
这样,一旦设置了停止事件,或者等待(即休眠)self.interval
秒后,线程就会唤醒。 (Event docs)
答案 2 :(得分:1)
感谢@ 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()
然后在主
interval = someinterval
callbacks = [some, callbacks]
f = Foo(interval, callbacks)
f.start()
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
f.kill()
raise