【问题标题】:Python Queue waiting for thread before getting next itemPython队列在获取下一个项目之前等待线程
【发布时间】:2011-05-18 03:52:47
【问题描述】:

我有一个队列,当它们被添加到它时,它总是需要准备好处理它们。在队列中的每个项目上运行的函数创建并启动线程以在后台执行操作,以便程序可以去做其他事情。

但是,我在队列中的每个项目上调用的函数只是启动线程然后完成执行,而不管它启动的线程是否完成。因此,在程序处理完最后一项之前,循环将转到队列中的下一项。

这是更好地展示我正在尝试做的事情的代码:

queue = Queue.Queue()
t = threading.Thread(target=worker)
t.start()

def addTask():
    queue.put(SomeObject())

def worker():
    while True:
        try:
            # If an item is put onto the queue, immediately execute it (unless 
            # an item on the queue is still being processed, in which case wait 
            # for it to complete before moving on to the next item in the queue)
            item = queue.get()
            runTests(item)
            # I want to wait for 'runTests' to complete before moving past this point
        except Queue.Empty, err:
            # If the queue is empty, just keep running the loop until something 
            # is put on top of it.
            pass

def runTests(args):
    op_thread = SomeThread(args)
    op_thread.start()
    # My problem is once this last line 't.start()' starts the thread, 
    # the 'runTests' function completes operation, but the operation executed
    # by some thread is not yet done executing because it is still running in
    # the background. I do not want the 'runTests' function to actually complete
    # execution until the operation in thread t is done executing.
    """t.join()"""
    # I tried putting this line after 't.start()', but that did not solve anything.
    # I have commented it out because it is not necessary to demonstrate what 
    # I am trying to do, but I just wanted to show that I tried it.

一些注意事项:

这一切都在 PyGTK 应用程序中运行。 'SomeThread' 操作完成后,它会向 GUI 发送回调以显示操作结果。

我不知道这对我遇到的问题有多大影响,但我认为这可能很重要。

【问题讨论】:

  • 我不明白这个问题。您可以使用Thread.join 暂停执行,直到线程完成,如果这是您正在寻找的。但是,你的问题很不清楚。
  • 您分配 t 两次,一次在全局范围内,一次在 runTests 函数中。这真的是一个有代表性的例子吗?您能否向我们展示一个完整的代码示例来说明您遇到的问题?
  • 我的代码实际上并非如此。我试图用更简单的术语来表达我想做的事情,并摆脱了每个函数中发生的所有实际数据处理。无论如何,我正在考虑只写出我想做的伪代码,看看是否有人知道怎么做,因为我患有临界性唐氏综合症,无法正确传达我的问题。

标签: python multithreading queue


【解决方案1】:

Python 线程的一个基本问题是你不能直接杀死它们——它们必须同意死亡

你应该做的是:

  1. 将线程实现为一个类
  2. 添加一个threading.Event 成员,join 方法会清除该成员,并且线程的主循环偶尔会检查该成员。如果它看到它被清除,它就会返回。为此覆盖 threading.Thread.join 以检查事件,然后自行调用 Thread.join
  3. 为了允许 (2),从 Queue 块读取一些小的超时。这样,您的线程对终止请求的“响应时间”将是超时,并且 OTOH 不会完成 CPU 阻塞

这里有一些来自套接字客户端线程的代码,它与阻塞队列有同样的问题:

class SocketClientThread(threading.Thread):
    """ Implements the threading.Thread interface (start, join, etc.) and
        can be controlled via the cmd_q Queue attribute. Replies are placed in
        the reply_q Queue attribute.
    """
    def __init__(self, cmd_q=Queue.Queue(), reply_q=Queue.Queue()):
        super(SocketClientThread, self).__init__()
        self.cmd_q = cmd_q
        self.reply_q = reply_q
        self.alive = threading.Event()
        self.alive.set()
        self.socket = None

        self.handlers = {
            ClientCommand.CONNECT: self._handle_CONNECT,
            ClientCommand.CLOSE: self._handle_CLOSE,
            ClientCommand.SEND: self._handle_SEND,
            ClientCommand.RECEIVE: self._handle_RECEIVE,
        }

    def run(self):
        while self.alive.isSet():
            try:
                # Queue.get with timeout to allow checking self.alive
                cmd = self.cmd_q.get(True, 0.1)
                self.handlers[cmd.type](cmd)
            except Queue.Empty as e:
                continue

    def join(self, timeout=None):
        self.alive.clear()
        threading.Thread.join(self, timeout)

注意self.aliverun 中的循环。

【讨论】:

  • 我最终在我的程序中发现了问题(一个 BASH 脚本在一个很远很远的外部系统中,它与进程混淆了[可能表明我的程序设计不佳,但这是一个问题再次])。但是,这是一个非常好的答案,并且比我最终做的要优雅得多。一旦我理解了你的代码,我将尝试在我的代码中实现类似的东西。如果我有代表这样做,我会这样做。
  • @Kededro:np。如果您需要帮助理解它,请随时在评论中提问
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-22
  • 1970-01-01
  • 2011-10-31
  • 2013-05-21
相关资源
最近更新 更多