python多线程队列没有运行或干净地退出

Posted

技术标签:

【中文标题】python多线程队列没有运行或干净地退出【英文标题】:python multithreading queues not running or exiting cleanly 【发布时间】:2016-07-23 19:48:10 【问题描述】:

我正在学习 python 多线程和队列。下面创建了一堆线程,它们通过队列将数据传递到另一个线程进行打印:

import time
import threading
import Queue

queue = Queue.Queue()

def add(data):
    return ["%sX" % x for x in data]

class PrintThread(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def run(self):
        data = self.queue.get()
        print data
        self.queue.task_done()

class MyThread(threading.Thread):
    def __init__(self, queue, data):
        threading.Thread.__init__(self)
        self.queue = queue
        self.data = data

    def run(self):
        self.queue.put(add(self.data))

if __name__ == "__main__":
    a = MyThread(queue, ["a","b","c"])
    a.start()
    b = MyThread(queue, ["d","e","f"])
    b.start()
    c = MyThread(queue, ["g","h","i"])
    c.start()

    printme = PrintThread(queue)
    printme.start()

    queue.join()

但是,我只看到打印出来的第一个线程的数据:

['aX', 'bX', 'cX']

然后没有别的,但程序没有退出。我必须终止进程才能让它退出。

理想情况下,在每个MyThread 进行数据处理并将结果放入队列之后,该线程应该退出吗?同时PrintThread 应该获取队列中的任何内容并打印出来。

在所有MyThread 线程完成并且PrintThread 线程完成处理队列中的所有内容之后,程序应该干净地退出。

我做错了什么?

编辑

如果每个MyThread 线程都需要一段时间来处理,有没有办法保证PrintThread 线程会等待所有MyThread 线程完成后再退出?

这样打印线程肯定会处理队列中所有可能的数据,因为所有其他线程都已经退出。

例如,

class MyThread(threading.Thread):
    def __init__(self, queue, data):
        threading.Thread.__init__(self)
        self.queue = queue
        self.data = data

    def run(self):
        time.sleep(10)
        self.queue.put(add(self.data))

上述修改将等待 10 秒,然后再将任何内容放入队列。打印线程会运行,但我认为它退出太早了,因为队列上还没有数据,所以程序什么也没打印出来。

【问题讨论】:

【参考方案1】:

您的PrintThread 不会循环,而是仅打印出单个队列项,然后停止运行。

因此,队列永远不会为空,queue.join() 语句将阻止主程序终止

PrintThreadrun() 方法更改为以下代码,以便处理所有队列项:

try:
    while True:
        data = self.queue.get_nowait()
        print data
        self.queue.task_done()
except queue.Empty:
    # All items have been taken off the queue
    pass

【讨论】:

你如何解决MyThread线程都需要5+秒来处理的问题?例如,如果我们在MyThread中将time.sleep(20)放在run()之后,则最终结果为空;什么都没有打印出来。有没有办法保证PrintThread 是最后一个退出的线程?这样可以保证所有数据都在队列中,并且 PrintThread 有机会处理它们,而不管其他线程处理数据所花费的时间。 您需要保持PrintThread 运行,例如通过将其创建为daemon thread。另一种方法是使用threading.Event 来通知线程停止主程序(因为线程本身不知道是否期望队列中有更多项目)。 我设置了printme.setDaemon(True),但程序正在打印一些奇怪的输出。例如,我看到像['gX', 'hX'['aX', 'bX', 'cX'] ['gX', 这样的损坏列表。这是个问题吗? 在 Python 2 中使用 print 不是线程安全的。请参阅this 和this SO 问题。

以上是关于python多线程队列没有运行或干净地退出的主要内容,如果未能解决你的问题,请参考以下文章

线程 python 应用程序没有干净地关闭

python 学习

在子进程运行和通信时终止子进程,这些子进程通过队列干净地通信

如何使用 Ctrl+C 输入干净地退出 QProcess?

从 Perl 线程中干净地退出

求助python多线程,执行到100多个停止了