一个多线程的python程序永远不会退出
Posted
技术标签:
【中文标题】一个多线程的python程序永远不会退出【英文标题】:A multi-threaded python program never exit 【发布时间】:2016-06-19 14:07:40 【问题描述】:我尝试使用 python 3.4.3 解释器在多线程 python 程序下运行。 我的期望是,dish_queue 中的所有项都被获取并处理完之后(这就是函数 task_done 的目的吧?),dish_queue 不会再阻塞程序,所以程序可以正常退出。
结果是在打印出Drying desert <Thread(Thread-2, started 140245865154304)>
行之后,无论dish_queue.join()
行是否被注释,程序都不会退出。
似乎主线程卡在声明 washer(dishes,dish_queue)
中?谁能给我解释一下为什么?
$ cat threading_dish.py
import threading,queue
import time
def washer(dishes,dishqueue):
for dish in dishes:
time.sleep(5)
print("washing",dish,threading.current_thread())
time.sleep(5)
dishqueue.put(dish)
def dryer(dishqueue):
while True:
dish=dishqueue.get()
print("Drying",dish,threading.current_thread())
#time.sleep(10)
dishqueue.task_done()
dish_queue=queue.Queue()
for n in range(2):
dryer_thread=threading.Thread(target=dryer,args=(dish_queue,))
dryer_thread.start()
dishes=['salad','bread','entree','desert']
washer(dishes,dish_queue)
#dish_queue.join()
$ python3 threading_dish.py
washing salad <_MainThread(MainThread, started 140245895784256)>
Drying salad <Thread(Thread-1, started 140245873547008)>
washing bread <_MainThread(MainThread, started 140245895784256)>
Drying bread <Thread(Thread-2, started 140245865154304)>
washing entree <_MainThread(MainThread, started 140245895784256)>
Drying entree <Thread(Thread-1, started 140245873547008)>
washing desert <_MainThread(MainThread, started 140245895784256)>
Drying desert <Thread(Thread-2, started 140245865154304)>
相比之下,如果我运行程序的多处理副本,程序可以在最后一次打印输出后正常退出。 多线程的和多处理的有什么区别导致相反的运行结果吗?
$ cat multiprocessing_dishes.py
import multiprocessing as mp
import time
def washer(dishes,output):
for dish in dishes:
print('washing', dish, 'dish',mp.current_process())
output.put(dish)
def dryer(input):
while True:
dish=input.get()
print('Drying',dish,'dish',mp.current_process())
time.sleep(5)
input.task_done()
dishqueue=mp.JoinableQueue()
dryerproc=mp.Process(target=dryer,args=(dishqueue,))
dryerproc.daemon=True
dryerproc.start()
dishes=['xxx','asa','aass']
washer(dishes,dishqueue)
dishqueue.join()
$ python3 multiprocessing_dishes.py
washing xxx dish <_MainProcess(MainProcess, started)>
washing asa dish <_MainProcess(MainProcess, started)>
washing aass dish <_MainProcess(MainProcess, started)>
Drying xxx dish <Process(Process-1, started daemon)>
Drying asa dish <Process(Process-1, started daemon)>
Drying aass dish <Process(Process-1, started daemon)>
$
【问题讨论】:
【参考方案1】:https://docs.python.org/3.4/library/queue.html
Queue.get() 阻塞,因此在不再生成队列后,您的干燥器线程将无限期阻塞。 您需要以某种方式向烘干机线程发出洗涤过程已完成的信号。
您可以通过在 while 循环的条件中查询一个共享变量来实现这一点,或者通过为每个线程排队一个毒丸来实现。毒丸是一个预先确定的值,它让消费线程知道它需要终止。
【讨论】:
我附加了程序的多处理副本,并且 JoinableQueue.get() 没有阻塞。为什么会有这样的区别? 在第二个例子中,dryer 线程是一个守护线程。守护线程是不阻止终止的线程。换句话说,如果应用程序的所有可运行和阻塞线程都是守护线程,那么应用程序将终止。烘干机线程 do 阻塞在 Queue.get() 上,它们只是不会阻止进程终止,并且一旦主线程完成执行,进程就会终止。我会说这通常是一个糟糕的解决方案,因为如果主线程(或另一个非守护线程)有更多工作要做,那么守护线程将保持阻塞状态。以上是关于一个多线程的python程序永远不会退出的主要内容,如果未能解决你的问题,请参考以下文章
python标准库学习thread,threading多线程的介绍和使用