考虑以下我一直在学习多线程的例子。它只是Python 3.5 queue documentation的扩展示例。
它会在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()
如果我按原样运行脚本(没有KeyboardInterrupt),它将不会终止。我必须杀死信号。但是,如果我评论/取消注释以下行(不使用事件并以文档方式执行...)
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放入队列,会有什么解决方案?
答案 0 :(得分:0)
有两种类型的线程:守护进程和非守护进程。默认情况下,所有线程都是非守护进程。只要至少有一个非守护程序线程,该进程就会保持活动状态。
这意味着要停止该过程,您必须:
None
让工作人员摆脱q.get()
中的无限等待;或