一个多线程的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多线程的介绍和使用

sys.exit()在Python多线程内调用时不会退出

python 学习

使用 MFC 清除 ONC RPC SVC_RUN() 退出

读者线程没有退出 - Posix Pthreads

python多线程学习记录