我正在使用一个重量级使用I / O的库。因此,对该库的调用可能持续很长时间(超过5秒)。
直接在UI
中使用它不是一个好主意,因为它会冻结。
出于这个原因,我将库调用外包给了一个线程队列,如下例所示:Python threads: communication and stopping
尽管如此,我对这个解决方案并不满意,因为这有一个主要的缺点:
每个lib命令都返回一条返回消息,该消息可以是错误消息或某些计算结果。 我怎么能得到这个?
考虑使用库调用do_test(foo)
:
def do_test(foo):
time.sleep(10)
return random.random() * foo
def ui_btn_click():
threaded_queue.put((do_test, 42))
# Now how to display the result without freezing the UI?
有人可以给我建议如何实现这种模式吗?
修改 这是一个最小的例子:
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相关的库。
答案 0 :(得分:0)
我想了一下我的实现。结论是我开始另一个挑选队列结果的线程:
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或其他地方的给定回调。