PyQt4、QThread与打开大文件不冻结GUI
我想问一下,怎么才能从磁盘读取一个大文件,同时让PyQt4的界面保持响应,不会卡住。我把文件加载的部分放到了一个QThread的子类里,但我的界面线程还是卡住了。有没有什么建议?我觉得这可能和全局解释器锁(GIL)有关,但我不知道该怎么解决。
补充说明:我正在使用来自GDCM项目的vtkGDCMImageReader来读取多帧的DICOM图像,并用vtk和pyqt4显示它。我是在一个不同的线程(QThread)中进行加载的,但我的应用程序在图像加载完成之前会一直卡住。下面是一个示例代码:
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())
4 个回答
1
看看这个链接:在PyQt应用中使用Qt线程还是Python线程
2
虽然有点晚了,但我觉得我能找出你遇到的问题。
你的图片很大,解压缩这个图片可能会占用很多CPU资源。这就意味着你的图形界面(GUI)线程会“休眠”,而加载线程则被CPU占满。此时,加载线程获得了全局解释器锁(GIL),而图形界面无法启动。
即使你能进入加载线程,并在里面加一个sleep(0),让图形界面继续运行,这在多核或多处理器的机器上也没什么用。发生的情况是操作系统有两个线程,它认为可以同时运行这两个线程。假设加载线程在核心1上运行,而图形界面在核心2上加载和运行。于是,在启动加载和图形界面线程后,操作系统在核心1上恢复加载线程,这个线程立刻获得了GIL。过了一会儿,图形界面线程准备好启动了,但它尝试获取GIL时失败了。没有GIL,它只能再次“休眠”!
一个解决方案是在后台线程中定期插入一个短暂的(大于零的)休眠,这样图形界面就能运行。但这并不总是可行的。
3
我猜你是直接调用了 run
来启动线程。这会导致图形界面卡住,因为你没有正确启动线程。
所以你缺少了 start
,它会间接并正确地调用 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()