Python - 线程在一种情况下终止。在另一个他们没有。为什么?



考虑下面我一直在学习多线程的例子。这只是 Python 3.5 队列文档的一个扩展示例。

它通过 4 个线程打印一些数字,在队列中生成一个错误,重试此元素,如果发生 KeyboardInterrupt 异常,应打印剩余的队列。

import threading
import queue
import time
import random
import traceback

def worker(q, active):
    while True:
        worker_item = q.get()
        #if worker_item == None:
        if not active.is_set():
            break
        time.sleep(random.random())
        with threading.Lock():
            if worker_item == 5 or worker_item == '5':
                try:
                    print(threading.current_thread().name + ': ' + worker_item + ' | remaining queue: ' + str(list(q.queue)))
                except TypeError:
                    print(threading.current_thread().name + ': ')
                    print(traceback.format_exc())
                    q.put(str(worker_item))
            else:
                print(threading.current_thread().name + ': ' + str(worker_item) + ' | remaining queue: ' + str(list(q.queue)))
        q.task_done()

def main():
    # INITIALIZE
    num_threads = 4
    stack1 = list(range(1, 21))
    stack2 = list(range(101, 121))
    q = queue.Queue()
    active = threading.Event()
    active.set()
    # START THREADS
    threads = []
    for _ in range(num_threads):
        t = threading.Thread(target=worker, args=(q, active))
        t.start()
        threads.append(t)
    try:
        # PUT STACK ITEMS ON QUEUE AND BLOCK UNTIL ALL TASKS ARE DONE
        for stack1_item in stack1:
            q.put(stack1_item)
        q.join()
        for stack2_item in stack2:
            q.put(stack2_item)
        q.join()
        # STOP WORKER LOOP IN EVERY THREAD
        #for _ in threads:
            #q.put(None)
        active.clear()
        # WAIT UNTIL ALL THREADS TERMINATE
        for t in threads:
            t.join()
    except KeyboardInterrupt:
        print(traceback.format_exc())
        print('remaining queue: ' + str(list(q.queue)))
        #for _ in threads:
            #q.put(None)
        active.clear()
        for t in threads:
            t.join()

if __name__ == '__main__':
    main()

如果我按原样运行脚本(没有键盘中断(,它不会终止。我必须杀死信号。 但是如果我评论/取消评论以下行(不使用事件并以文档方式进行......

comment / worker / if not active.is_set():
uncomment / worker / #if worker_item == None:
comment / main / active.clear()
uncomment / main / #for _ in threads:
                       #q.put(None)
comment / main / except / active.clear()
uncomment / main / except / #for _ in threads:
                                #q.put(None)

它确实以退出代码 0 退出。为什么?

为什么需要将 Nones 放入队列?如果不将 Nones 放入队列,解决方案是什么?

有两种类型的线程:守护程序和非守护进程。默认情况下,所有线程都是非守护程序。只要至少有一个非守护程序线程,进程就会保持活动状态。

这意味着要停止该过程,您必须:

  1. 停止它的所有线程(这是你注释掉的代码通过使用None将工作线程踢出无限等待q.get()所做的(;或者
  2. 使 worker 守护进程线程,在这种情况下,
  3. 进程将在主线程停止后立即停止(如果要确保 worker 已完成其任务,这将需要格外小心(。

相关内容

最新更新