python多线程无法退出?

由于代码第26行设置了daemon=False这个多线程程序无法退出,如果改为daemon=True就没事了。代码可以直接运行

p.s: basic_worker里面我设置了while循环的break条件。

为什么会产生这样的情况呢?

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import Queue
import threading

def basic_worker(queue):
    """
    工作者,当队列中没有任务的时候就执行退出。
    """
    while True:
        item = queue.get()
        if item is None:
            break
        print item
        queue.task_done()


def basic():
    """
    主线程,队列中总共放了4个任务。
    """
    print 'start'
    queue = Queue.Queue()
    for i in range(4):
        t = threading.Thread(target=basic_worker, args=(queue,))
        t.daemon = False # 这里daemon必须等于True才能程序才能退出
        t.start()
    for item in range(4):
        queue.put(item)
    queue.join()       # block until all tasks are done
    print 'got here'

if __name__ == '__main__':
    basic()
阅读 14.6k
5 个回答

初步判断这个问题和Queue模块的get()函数有关,该函数的定义是

Queue.get([block[, timeout]])

函数说明如下:

   从队列中移除并返回一个数据。如果可选的参数block为真且timeout为空对象(默认的情况,阻塞调用,无超时),
    阻塞调用进程直到有数据可用。如果timeout是个正整数,阻塞调用进程最多timeout秒,
    如果一直无数据可用,抛出Empty异常(带超时的阻塞调用)。如果block为假,
    如果有数据可用返回数据,否则立即抛出Empty异常(非阻塞调用,timeout被忽略)。

如果queue队列为空了,它会一直堵塞进程直到有数据可用,所以退不出程序
如果设置queue.get(True, 1),超时后就会抛出异常

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import Queue
import threading

def basic_worker(queue):
    """
    工作者,当队列中没有任务的时候就执行退出。
    """
    while True:
        try:
            item = queue.get(True,1)
        except :
            queue.task_done()
            break
        print('[%s]get %d'%(threading.current_thread(),item))
        #queue.task_done()


def basic():
    """
    主线程,队列中总共放了4个任务。
    """
    print 'start'
    queue = Queue.Queue()
    for i in range(4):
        t = threading.Thread(target=basic_worker, args=(queue,))
        t.daemon = False # 这里daemon必须等于True才能程序才能退出
        t.start()
    for item in range(4):
        queue.put(item)
    queue.join()       # block until all tasks are done
    print 'got here'

if __name__ == '__main__':
    basic()

我修改了你的代码,就可以在1秒没有数据就退出。

泻药~

python3

import queue
import threading

def basic_worker(queue,lck):
    """
    工作者,当队列中没有任务的时候就执行退出。
    """
    #队列空了,就结束任务
    while not queue.empty():
        item = queue.get()
        lck.acquire()
        print (item)
        lck.release()
        queue.task_done() 


def basic():
    """
    主线程,队列中总共放了4个任务。
    """
    print ('start')
    lck = threading.Lock()
    q = queue.Queue()
    for item in range(4):
        q.put(item)
        
    for i in range(4):
        t = threading.Thread(target=basic_worker, args=(q,lck))
        t.start()
        
    q.join()       # block until all tasks are done

    print ('got here')

if __name__ == '__main__':
    basic()

感谢邀请,同意@郭伟匡的说法。
当子线程daemon=False时,主线程会等待它们退出后才会退出,
由于queue.get默认在拿不到数据时一直阻塞,所有整个程序不会退出。
当子线程daemon=True时,主线程会直接退出并强制使它们退出,所以看上去会正常退出。

迷惑中,我跟楼主同样提问

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏