Reputation: 8203
I am building an application with a GUI and several worker threads. Now I want it to be a multi-threaded application so I am executing the same thread several times, in a loop, each thread grabbing different input parameters defined in a class outside of the thread.
So my mainGui.py file looks something like this (relevant code shown only):
self.workers = [worker.Worker(), worker.Worker(), worker.Worker()]
for i in xrange(threadCount):
self.currentWorker = self.workers[i]
self.currentWorker.alterTable.connect(self.alterMainTable)
self.currentWorker.start()
time.sleep(0.1)
As you may imagine, I am connecting the Worker's alterTable
signal to the alterMainTable()
method I have defined in my main GUI thread. This method updates the table in the GUI.
The worker thread looks something like this:
class Worker(QThread):
alterTable = Signal(dict)
def __init__(self, parent=None):
super(Worker, self).__init__(parent)
def sendToTable(self, param1, param2, param3):
"""This method emits the signal with params as defined above"""
params = {}
params["param1"] = param1
params["param2"] = param2
params["param3"] = param3
self.alterTable.emit(params)
def run(self):
#Perform a lengthy task, do this every now and then:
self.sendToTable(param, param2, param3)
When I am running this application in a single worker thread (so when I'm not calling that loop in the main thread), it works fine - the signals are emitted, and the main table in the GUI is updated.
However, the problems arise when I run several threads at once. The Worker threads do their job, but the Signal is only emitted sometimes. Or, better yet, it is emitted as if Qt (or whatever) was waiting for all the threads to finish, and then update the table. This is literally what happens - I can see in Python console that the threads are performing their tasks, and once all of them are doing whatever they were doing, the table is suddenly populated with a bunch of data at once.
As you may imagine, another problem that comes out of this is that since there are no events being processed, after some time, my application appears to be frozen.
I have tried adding the Qt.DirectConnection
to the connect()
method, but that didn't really help.
Bonus question: I've been reading about this topic on SO and other websites, it seems that people recommend QRunnable()
instead of QThread()
especially when it comes to subclassing it. Consequently, I'd be using QThreadPool()
. But when I tried this, it seems that I cannot emit a signal from a QRunnable
- it gives me the AttributeError: 'PySide.QtCore.Signal' object has no attribute 'connect'
, even though the Signal is defined within the QRunnable class - which is quite odd, I must say.
EDIT: In another answer on SO, someone mentioned that one may be "spamming" the main GUI thread with events to be processed. However, I don't believe that this is the case here as the sendToTable()
method from the QThread is only called 5-6 times at most from the thread, and the threadCount
is never larger than 20 at most, but I usually keep it at around 5.
Upvotes: 2
Views: 579
Reputation: 8203
And, as usual, I answer my question after 2 days of debugging and minutes after posting on SO.
I had a leftover workerThread.wait()
method call after all the threads have been started. So naturally my application did what it was told to do - waited for the thread to finish.
I removed that method call and also put the QCoreApplication.processEvents()
inside the loop which started the threads, now it all works like a charm.
Once again, thank you, the invisible, almighty person of SO!
Upvotes: 3