I'm trying to do a fairly common thing in my PySide GUI application: I want to delegate some CPU-Intensive task to a background thread so that my GUI stays responsive and could even display a progress indicator as the computation goes.
Here is what I'm doing (I'm using PySide 1.1.1 on Python 2.7, Linux x86_64):
from PySide.QtGui import QMainWindow, QPushButton, QApplication, QWidget
from PySide.QtCore import QThread, QObject, Signal, Slot
done_signal = Signal()
def __init__(self, parent = None):
print "[thread %x] computation started" % self.thread().currentThreadId()
for i in range(30):
x = 1000000
y = 100**x
print "[thread %x] computation ended" % self.thread().currentThreadId()
self.work_thread = QThread()
self.worker = Worker()
self.btn = QPushButton('Do stuff', self)
self.setGeometry(300, 300, 250, 150)
print "[main %x] started" % (self.thread().currentThreadId())
print "[main %x] ended" % (self.thread().currentThreadId())
app = QApplication(sys.argv)
ex = Example()
if __name__ == '__main__':
This is probably caused by the worker thread holding Python's GIL. In some Python implementations, only one Python thread can execute at a time. The GIL prevents other threads from executing Python code, and is released during function calls that don't need the GIL.
For example, the GIL is released during actual IO, since IO is handled by the operating system and not the Python interpreter.
Apparently, you can use
time.sleep(0) in your worker thread to yield to other threads (according to this SO question). You will have to periodically call
time.sleep(0) yourself, and the GUI thread will only run while the background thread is calling this function.
If the worker thread is sufficiently self-contained, you can put it into a completely separate process, and then communicate by sending pickled objects over pipes. In the foreground process, create a worker thread to do IO with the background process. Since the worker thread will be doing IO instead of CPU operations, it won't hold the GIL and this will give you a completely responsive GUI thread.
Some Python implementations (JPython and IronPython) do not have a GIL.
Threads in CPython are only really useful for multiplexing IO operations, not for putting CPU-intensive tasks in the background. For many applications, threading in the CPython implementation is fundamentally broken and it is likely to stay that way for the forseeable future.