[英]Python how to kill threads blocked on queue with signals?
我在队列上启动了一堆线程,我想在发送 SIGINT (Ctrl+C) 时杀死它们。 处理这个问题的最佳方法是什么?
targets = Queue.Queue()
threads_num = 10
threads = []
for i in threads_num:
t = MyThread()
t.setDaemon(True)
threads.append(t)
t.start()
targets.join()
如果您不想让其他线程正常关闭,只需以守护进程模式启动它们并将队列的加入包装在终止线程中。
这样,您可以使用线程的join
方法——它支持超时并且不会阻止异常——而不必等待队列的join
方法。
换句话说,做这样的事情:
term = Thread(target=someQueueVar.join)
term.daemon = True
term.start()
while (term.isAlive()):
term.join(3600)
现在,Ctrl+C 将终止 MainThread,然后 Python 解释器硬杀死所有标记为“守护进程”的线程。 请注意,这意味着您必须为所有其他线程设置“Thread.daemon”,或者通过捕获正确的异常(KeyboardInterrupt 或 SystemExit)并执行任何需要为它们退出的操作来优雅地关闭它们。
另请注意,您绝对需要将一个数字传递给term.join()
,否则它也会忽略所有异常。 不过,您可以选择任意大的数字。
不是Ctrl + C SIGINT
吗?
无论如何,您可以为适当的信号安装一个处理程序,并在处理程序中:
等等。主要取决于您要中断的应用程序的结构。
一种方法是为SIGTERM
安装一个直接调用os._exit(signal.SIGTERM)
的信号处理程序。 但是,除非您为Queue.get
指定可选的timeout
参数, Queue.get
信号处理函数将在get
方法返回后才会运行。 (这完全没有记录;这是我自己发现的。)因此,您可以将sys.maxint
指定为超时,并将Queue.get
调用置于重试循环中以解决该问题。
这就是我解决这个问题的方式。
class Worker(threading.Thread):
def __init__(self):
self.shutdown_flag = threading.Event()
def run(self):
logging.info('Worker started')
while not self.shutdown_flag.is_set():
try:
task = self.get_task_from_queue()
except queue.Empty:
continue
self.process_task(task)
def get_task_from_queue(self) -> Task:
return self.task_queue.get(block=True, timeout=10)
def shutdown(self):
logging.info('Shutdown received')
self.shutdown_flag.set()
收到信号后,主线程在工作线程上设置关闭事件。 工作人员在阻塞队列中等待,但每 10 秒检查一次是否收到关闭信号。
为什么不为队列上的任何操作设置超时? 然后您的线程可以通过检查是否引发事件来定期检查它们是否必须完成。
我设法通过清空KeyboardInterrupt
上的队列并让线程优雅地停止自己来解决这个问题。
我不知道这是否是处理这个问题的最好方法,但它很简单而且很干净。
targets = Queue.Queue()
threads_num = 10
threads = []
for i in threads_num:
t = MyThread()
t.setDaemon(True)
threads.append(t)
t.start()
while True:
try:
# If the queue is empty exit loop
if self.targets.empty() is True:
break
# KeyboardInterrupt handler
except KeyboardInterrupt:
print "[X] Interrupt! Killing threads..."
# Substitute the old queue with a new empty one and exit loop
targets = Queue.Queue()
break
# Join every thread on the queue normally
targets.join()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.