Python 如何与工作线程通信

Python 如何与工作线程通信,python,multithreading,concurrency,threadpool,Python,Multithreading,Concurrency,Threadpool,我正在使用一个大量使用I/O的库。因此,对该库的调用可能会持续很长时间,可能超过5秒。 直接在UI中使用它不是一个好主意,因为它会冻结 因此,我将库调用外包给一个线程队列,如本例所示: 然而,我对该解决方案不太满意,因为它有一个主要缺点: 我真的无法与UI进行通信。 每个lib命令都返回一条返回消息,该消息可以是错误消息,也可以是某些计算结果。 我怎样才能得到这个 考虑一个库调用do_testfoo: 有人能给我建议如何实现这种模式吗 编辑: 这是一个简单的例子: import os, time

我正在使用一个大量使用I/O的库。因此,对该库的调用可能会持续很长时间,可能超过5秒。 直接在UI中使用它不是一个好主意,因为它会冻结

因此,我将库调用外包给一个线程队列,如本例所示:

然而,我对该解决方案不太满意,因为它有一个主要缺点:

我真的无法与UI进行通信。 每个lib命令都返回一条返回消息,该消息可以是错误消息,也可以是某些计算结果。 我怎样才能得到这个

考虑一个库调用do_testfoo:

有人能给我建议如何实现这种模式吗

编辑: 这是一个简单的例子:

import os, time, random
import threading, queue

CMD_FOO = 1
CMD_BAR = 2

class ThreadedQueue(threading.Thread):
    def __init__(self):
        super().__init__()
        self.in_queue = queue.Queue()
        self.out_queue = queue.Queue()
        self.__stoprequest = threading.Event()

    def run(self):
        while not self.__stoprequest.isSet():
            (cmd, arg) = self.in_queue.get(True)

            if cmd == CMD_FOO:
                ret = self.handle_foo(arg)
            elif cmd == CMD_BAR:
                ret = self.handle_bar(arg)
            else:
                print("Unsupported cmd {0}".format(cmd))
            self.out_queue.put(ret)
            self.in_queue.task_done()

    def handle_foo(self, arg):
        print("start handle foo")
        time.sleep(10)
        return  random.random() * arg

    def handle_bar(self, arg):
        print("start handle bar")
        time.sleep(2)
        return (random.random() * arg, 2 * arg)


if __name__ == "__main__":
    print("START")
    t = ThreadedQueue()
    t.start()
    t.in_queue.put((CMD_FOO, 10))
    t.in_queue.put((CMD_BAR, 10))

    print("Waiting")

    while True:
        x = t.out_queue.get(True)
        t.out_queue.task_done()
        print(x)

我个人使用PySide,但我不想将这个库依赖于PySide或任何其他与ui相关的库。

我对我的实现进行了一些思考。结论是,我启动了另一个线程来拾取队列的结果:

class ReceiveThread(threading.Thread):
    """
    Processes the output queue and calls a callback for each message
    """
    def __init__(self, queue, callback):
        super().__init__()
        self.__queue = queue
        self.__callback = callback
        self.__stoprequest = threading.Event()
        self.start()

    def run(self):
        while not self.__stoprequest.isSet():
            ret = self.__queue.get(True)
            self.__callback(ret)
            self.__queue.task_done()

来自UI或其他地方的给定回调将随队列中的每个结果一起调用。

如果不看到更多的代码,很难变得更具体,但一般的想法是,您有一个“工作”线程从一个队列中消费数据,并将结果放入另一个队列中,而另一个线程可以在其中消费数据。您的UI使用什么?你有一个ui线程运行应用程序的主“循环”吗?我已经用一个简单的例子进行了更新。我是否需要从第三个线程访问out_队列?我不确定是否理解您的问题。是不是不希望主线程等待结果?基本上是的。我希望附加的ui在执行长时间的ronning呼叫时感觉灵敏。由于这个原因,我已经完成了命令队列。但是如何用响应更新?我想你的代码差不多就在那里了-在“main”中的循环中,不要使用out queue.getTrue-True告诉线程阻塞,直到队列上有一个项目。在try内传递False或调用get_nowait…除了块和捕获空异常。这将防止主循环阻塞。
class ReceiveThread(threading.Thread):
    """
    Processes the output queue and calls a callback for each message
    """
    def __init__(self, queue, callback):
        super().__init__()
        self.__queue = queue
        self.__callback = callback
        self.__stoprequest = threading.Event()
        self.start()

    def run(self):
        while not self.__stoprequest.isSet():
            ret = self.__queue.get(True)
            self.__callback(ret)
            self.__queue.task_done()