【问题标题】:Python threads and queue examplePython 线程和队列示例
【发布时间】:2013-02-16 21:54:40
【问题描述】:

我是 python 新手(我来自 PHP),我一直在阅读教程并尝试了几天,但我无法理解这个队列示例 (http://docs.python.org/2/library/queue.html)

def worker():
    while True:
        item = q.get()
        do_work(item)
        q.task_done()

q = Queue()
for i in range(num_worker_threads):
     t = Thread(target=worker)
     t.daemon = True
     t.start()

for item in source():
    q.put(item)

q.join()       # block until all tasks are done

我不明白的是工作线程是如何完成和存在的。我已经阅读了 q.get() 阻塞,直到一个项目可用,所以如果所有项目都已处理并且队列中没有任何项目,为什么 q.get() 不会永远阻塞?

【问题讨论】:

    标签: python multithreading queue


    【解决方案1】:

    我也遇到了同样的问题。当所有线程都完成后,我在进程列表中看到“睡眠线程”(使用top -H -p <pid>,其中<pid> 是来自ps aux | grep python 的进程ID 与您的脚本)。

    我通过将“无限循环”while True 替换为 while not q.empty(): 解决了这个问题。

    它解决了“休眠线程”的问题。

    def worker():
        while not q.empty():
            item = q.get()
            do_work(item)
            q.task_done()
    
    q = Queue()
    for i in range(num_worker_threads):
         t = Thread(target=worker)
         t.daemon = True
         t.start()
    
    for item in source():
        q.put(item)
    
    q.join()       # block until all tasks are done
    

    【讨论】:

    • 该解决方案相当冒险。如果工作线程很快,他们会在将任何项目添加到队列之前测试q.empty(),然后在他们完成任何操作之前退出。同样,如果队列中只剩下一个项目并且两个线程同时测试q.empty(),它们都会继续,但一个会从队列中取出一个项目,而另一个会在q.get() 阻塞。
    【解决方案2】:

    在这段代码中线程没有正常退出(当队列为空时它们确实被阻塞了)。程序不会等待他们,因为他们是 daemon threads

    程序不会立即退出,也不会因为q.joinq.task_done 调用而永远阻塞。

    每当将项目添加到队列中时,未完成任务的计数就会增加。每当消费者线程调用task_done() 以指示该项目已被检索并且所有工作都已完成时,计数就会下降。当未完成任务的计数降至零时,join() 解除阻塞,程序无需等待守护线程即可存在。

    【讨论】: