gpt4 book ai didi

python - 如何从 QThread 和 Queue 运行的函数返回值

转载 作者:太空狗 更新时间:2023-10-29 21:24:14 25 4
gpt4 key购买 nike

请解释我们如何从队列管理的线程发送/接收数据....

首先,我将“QThread”子类化,定义其 run() 方法,该方法在 QThread.start() 被调用时启动:

class SimpleThread(QtCore.QThread):
def __init__(self, queue, parent=None):
QtCore.QThread.__init__(self, parent)
self.queue=queue
def run(self):
while True:
arg=self.queue.get()
self.fun(arg)
self.queue.task_done()
def fun(self, arg):
for i in range (3):
print 'fun: %s'%i
self.sleep(1)
return arg+1

然后我声明两个 Thread 实例(因此只使用两个 CPU 内核)发送 self.queue 实例作为参数。

self.queue=queue.Queue()
for i in range(2):
thread=SimpleThread(self.queue)
thread.start()

现在,如果我理解正确的话,thread.start() 没有启动任何东西。真正的“开始”仅在我调用 queue.put() 时发生:

for arg in [1,2,3]: self.queue.put(arg)

最后一行是进行“真实”调用的内容。除了创建和启动队列项之外,put() 允许将任意值保存到每个队列项.put() 同时做几件事:它创建,它开始,它在队列中移动处理,它允许在队列项的“内部”放置一个变量(稍后可以检索)从函数处理器内部:使用队列项的“.get()”方法)。

但是如何从 fun() 函数返回值。 “常规”fun()return resultValue 不起作用。而且我不能使用 self.queue.put() 方法,因为除了存储数据之外,此方法还“创建”了一个新的队列项...

稍后编辑:

这里是稍微调整过的代码(从另一篇文章复制/粘贴),展示了如何从完成的线程返回值的方法。我不确定这里使用的方法是否适用于 QThread...如果我错了请纠正我:

import os, sys
import threading
import Queue

def callMe(incomingFun, daemon=False):
def execute(_queue, *args, **kwargs):
result=incomingFun(*args, **kwargs)
_queue.put(result)

def wrap(*args, **kwargs):
_queue=Queue.Queue()
_thread=threading.Thread(target=execute, args=(_queue,)+args, kwargs=kwargs)
_thread.daemon=daemon
_thread.start()
_thread.result_queue=_queue
return _thread

return wrap

@callMe
def localFunc(x):
import time
x = x + 5
time.sleep(5)
return x

thread=localFunc(10)

# this blocks, waiting for the result
result = thread.result_queue.get()
print result

最佳答案

在正常情况下,您会使用结果队列将结果发回,然后让其他线程运行以等待结果:

class SimpleThread(QtCore.QThread):
def __init__(self, queue, result_queue, parent=None):
QtCore.QThread.__init__(self, parent)
self.queue=queue
self.result_queue = result_queue

def run(self):
while True:
arg=self.queue.get()
self.fun(arg)
self.queue.task_done()

def fun(self, arg):
for i in range (3):
print 'fun: %s'%i
self.sleep(1)
self.result_queue.put(arg+1)

def handle_results(result_queue):
while True:
result = result_queue.get()
print("Got result {}".format(result))

主线程:

self.queue=queue.Queue()
self.result_queue = queue.Queue()

result_handler = threading.Thread(target=handle_results, self.result_queue)
for i in range(2):
thread=SimpleThread(self.queue, self.result_queue)
thread.start()

这样做可以防止您在等待结果时阻塞 GUI 的事件循环。以下是 multiprocessing.pool.ThreadPool 的等价物:

from multiprocessing.pool import ThreadPool
import time


def fun(arg):
for i in range (3):
print 'fun: %s'%i
time.sleep(1)
return arg+1

def handle_result(result):
print("got result {}".format(result))

pool = ThreadPool(2)
pool.map_async(fun, [1,2,3], callback=handle_result)

这样就简单多了。它在内部创建一个结果处理线程,当 fun 完成时,它会自动为您调用 handle_result

就是说,您正在使用 QThread,并且您希望结果更新 GUI 小部件,因此您确实希望将结果发送回主线程,而不是结果处理线程.在这种情况下,使用 Qt 的信号系统是有意义的,这样您就可以在收到结果时安全地更新 GUI:

from PyQt4 import QtCore, QtGui
import sys
import Queue as queue

class ResultObj(QtCore.QObject):
def __init__(self, val):
self.val = val

class SimpleThread(QtCore.QThread):
finished = QtCore.pyqtSignal(object)

def __init__(self, queue, callback, parent=None):
QtCore.QThread.__init__(self, parent)
self.queue = queue
self.finished.connect(callback)

def run(self):
while True:
arg = self.queue.get()
if arg is None: # None means exit
print("Shutting down")
return
self.fun(arg)

def fun(self, arg):
for i in range(3):
print 'fun: %s' % i
self.sleep(1)
self.finished.emit(ResultObj(arg+1))


class AppWindow(QtGui.QMainWindow):
def __init__(self):
super(AppWindow, self).__init__()
mainWidget = QtGui.QWidget()
self.setCentralWidget(mainWidget)
mainLayout = QtGui.QVBoxLayout()
mainWidget.setLayout(mainLayout)
button = QtGui.QPushButton('Process')
button.clicked.connect(self.process)
mainLayout.addWidget(button)

def handle_result(self, result):
val = result.val
print("got val {}".format(val))
# You can update the UI from here.

def process(self):
MAX_CORES=2
self.queue = queue.Queue()
self.threads = []
for i in range(MAX_CORES):
thread = SimpleThread(self.queue, self.handle_result)
self.threads.append(thread)
thread.start()

for arg in [1,2,3]:
self.queue.put(arg)

for _ in range(MAX_CORES): # Tell the workers to shut down
self.queue.put(None)

app = QtGui.QApplication([])
window = AppWindow()
window.show()
sys.exit(app.exec_())

按下按钮时的输出:

fun: 0
fun: 0
fun: 1
fun: 1
fun: 2
fun: 2
fun: 0
got val 2
got val 3
Shutting down
fun: 1
fun: 2
Shutting down
got val 4

关于python - 如何从 QThread 和 Queue 运行的函数返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25108321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com