开发者

PyQt4, QThread and opening big files without freezing the GUI

I would like to ask how to read a big file from disk and maintain the PyQt4 UI responsive (not blocked). I had moved the load of the file to a QThread subclass but my GUI thread get freezed. Any suggestions? I think it must be something with the GIL but I don't know how to sort it?

EDIT: I am using vtkGDCMImageReader from the GDCM project to read a multiframe DICOM i开发者_如何学JAVAmage and display it with vtk and pyqt4. I do this load in a different thread (QThread) but my app freeze until the image is loaded. here is an example code:

class ReadThread(QThread): 
    def __init__(self, file_name): 
        super(ReadThread, self).__init__(self) 
        self.file_name = file_name 
        self.reader.vtkgdcm.vtkGDCMImageReader()

    def run(self): 
        self.reader.SetFileName(self.file_name) 
        self.reader.Update() 
        self.emit(QtCore.SIGNAL('image_loaded'), self.reader.GetOutput())


I'm guessing you're directly calling the run to begin the thread. That would make the GUI freeze because you're not activating the thread.

So you'd be missing the start there, which would indirectly and properly call the run:

thread = ReadThread()
thread.begin()

class ReadThread(QThread): 
    def __init__(self, file_name): 
        super(ReadThread, self).__init__(self) 
        self.file_name = file_name 
        self.reader.vtkgdcm.vtkGDCMImageReader()

    def run(self): 
        self.reader.SetFileName(self.file_name) 
        self.reader.Update() 
        self.emit(QtCore.SIGNAL('image_loaded'), self.reader.GetOutput())

    def begin(self): 
        self.start()


A bit late, but I think I can pinpoint the problem you face.

The image is large, and the unpacking is probably a CPU intensive task. This means that your GUI thread goes to sleep and the loading thread is CPU bound. At that point the loading thread has the GIL, and the GUI cannot start.

Even if you can get into the loading thread, and introduce a sleep(0), to alow the GUI to continue, this will not help on a mulit-core or multi-processor machine. What happens is the O/S has two threads and thinks it can run both. The loading thread is set up on (say) core 1 and the GUI can be loaded and run on (say) core 2. So after initiating the load and start of the GUI thread on core 2, the O/S resumes the loading thread on core 1 - which promtply grabs the GIL. Moments later the GUI thread is ready to start, and attempts to aquire the GIL, which fails. All it can do without the GIL is go back to sleep!

One solution is to insert a short (greater than zero) sleep in the background thread at strategic intervals, so that the GUI can run. This is not always possible.


Take a look at threading-in-a-pyqt-application-use-qt-threads-or-python-threads


Maybe create your reader object in the tread:

class ReadThread(QThread): 
    def __init__(self, file_name): 
        super(ReadThread, self).__init__(self) 
        self.file_name = file_name 
-       self.reader = vtkgdcm.vtkGDCMImageReader()

    def run(self): 
+       self.reader = vtkgdcm.vtkGDCMImageReader()
        self.reader.SetFileName(self.file_name) 
        self.reader.Update() 
        self.emit(QtCore.SIGNAL('image_loaded'), self.reader.GetOutput())
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜