Самый простой способ, чтобы начать все рабочие потоки, как демон потоков, то только ваш основной цикл будет
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. Конечно, с моими приведенными выше примерами вам не нужно присоединяться, но у вас может быть и другая причина для этого.
Так, в основном, используя q.join(), трудно справляться с исключениями в потоках? –
Должен ли он читать «сигнал (SIGINT, stop)»? – Ber
Это делает вещи более сложными, но я добавил пример с сигналами, чтобы показать вам, как вы будете использовать q.join(), если у вас есть веские основания для его использования. –