Ответ 1
Самый простой способ - запустить все рабочие потоки как потоки демона, а затем просто создать свой основной цикл
while True:
sleep(1)
Нажатие Ctrl + C вызовет исключение в вашем основном потоке, и все потоки демона выйдут, когда выйдет интерпретатор. Это предполагает, что вы не хотите выполнять очистку во всех этих потоках до их выхода.
Более сложным способом является глобальный stopped
Event:
stopped = Event()
def worker():
while not stopped.is_set():
try:
item = q.get_nowait()
do_work(item)
except Empty: # import the Empty exception from the Queue module
stopped.wait(1)
Тогда ваш основной цикл может установить событие stopped
на False
, когда он получит KeyboardInterrupt
try:
while not stopped.is_set():
stopped.wait(1)
except KeyboardInterrupt:
stopped.set()
Это позволяет вашим рабочим потокам завершить то, что они делают, а не просто, чтобы каждый рабочий поток был демонами и выходил в середине выполнения. Вы также можете делать любую очистку, которую хотите.
Обратите внимание, что этот пример не использует q.join()
- это делает вещи более сложными, хотя вы все равно можете их использовать. Если вы делаете, то лучше всего использовать обработчики сигналов вместо исключений для обнаружения KeyboardInterrupt
s. Например:
from signal import signal, SIGINT
def stop(signum, frame):
stopped.set()
signal(SIGINT, stop)
Это позволяет определить, что происходит, когда вы нажимаете Ctrl + C, не влияя на то, что ваш основной цикл находится посередине. Таким образом, вы можете продолжать делать q.join()
, не беспокоясь о прерывании Ctrl + C. Конечно, с моими приведенными выше примерами вам не нужно присоединяться, но у вас может быть и другая причина для этого.