How To Return Value From Function Running By Qthread And Queue
Solution 1:
In normal circumstances you'd use a result queue to send results back, and then have some other thread running that waits for the results:
classSimpleThread(QtCore.QThread):
def__init__(self, queue, result_queue, parent=None):
QtCore.QThread.__init__(self, parent)
self.queue=queue
self.result_queue = result_queue
defrun(self):
whileTrue:
arg=self.queue.get()
self.fun(arg)
self.queue.task_done()
deffun(self, arg):
for i inrange (3):
print'fun: %s'%i
self.sleep(1)
self.result_queue.put(arg+1)
defhandle_results(result_queue):
whileTrue:
result = result_queue.get()
print("Got result {}".format(result))
Main thread:
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()
Doing it this way will keep you from blocking the GUI's event loop while you wait for the results. Here's what the equivalent would look like with 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)
Which is a lot simpler. It internally creates a result handling thread, which will automatically call handle_result
for you when fun
completes.
That said, you're using QThread
, and you want the results to update GUI widgets, so you really want your results to be sent back to the main thread, not to a result handling thread. In that case, it makes sense to use Qt's signaling system, so that you can safely update the GUI when you receive the result:
from PyQt4 import QtCore, QtGui
import sys
import Queue as queue
classResultObj(QtCore.QObject):
def__init__(self, val):
self.val = val
classSimpleThread(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)
defrun(self):
whileTrue:
arg = self.queue.get()
if arg isNone: # None means exitprint("Shutting down")
return
self.fun(arg)
deffun(self, arg):
for i inrange(3):
print'fun: %s' % i
self.sleep(1)
self.finished.emit(ResultObj(arg+1))
classAppWindow(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)
defhandle_result(self, result):
val = result.val
print("got val {}".format(val))
# You can update the UI from here.defprocess(self):
MAX_CORES=2
self.queue = queue.Queue()
self.threads = []
for i inrange(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 _ inrange(MAX_CORES): # Tell the workers to shut down
self.queue.put(None)
app = QtGui.QApplication([])
window = AppWindow()
window.show()
sys.exit(app.exec_())
Output when the button is pushed:
fun: 0fun: 0fun: 1fun: 1fun: 2fun: 2fun: 0
got val2
got val3
Shutting down
fun: 1fun: 2
Shutting down
got val4
Post a Comment for "How To Return Value From Function Running By Qthread And Queue"