[英]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.