我在自定义窗口小部件类中有这段代码:
def import_data(self, fname):
worker = DataRead(fname)
readThread = QtCore.QThread(self)
worker.moveToThread(readThread)
readThread.started.connect(worker.read_data)
readThread.start()
'worker'类看起来像这样:
class DataRead(QtCore.QObject):
def __init__(self):
super(DataRead, self).__init__()
@QtCore.Slot()
def read_data(self):
print 'Hi!'
上面的代码不起作用。它仅在我将worker
实例存储为我的自定义窗口小部件类的属性时才有效。即:
def import_data(self, fname):
self.worker = DataRead(fname)
readThread = QtCore.QThread(self)
self.worker.moveToThread(readThread)
readThread.started.connect(self.worker.read_data)
readThread.start()
我真的无法理解为什么会这样?
此外,如果这是必需的,为什么QThread
实例(readThread
)也不是也需要存储为属性?
我用Google搜索并看到了很多关于'亲和力'和'坚持'的讨论,但没有什么能够真正解释它对我来说。
我想到的最后一个问题是......如果我必须创建worker
作为实例属性,那么这不会否定我随后调用的moveToThread
函数吗?
由于worker
现在链接到主GUI线程中的自定义窗口小部件,当线程信号调用self.worker.read_data
时,是否会在主线程中执行?
我的思绪转向果冻......
答案 0 :(得分:2)
您需要将工作程序存储为类属性的原因是由于您已声明的变量持久性。这与引用计数有关。每个Python对象都会记录自己有多少引用。对于对变量进行的每个新引用,计数都会递增。每次删除引用时,计数都会递减。当引用计数达到零时,该变量将进行垃圾收集并从内存中释放。
您的原始import_data
函数定义了工作线程,但是一旦控件返回到调用代码,引用就会超出范围,worker
将其引用数减少为零,并且因此从内存中删除。由于线程的整个要点是并行执行,因此当您调用readThread.start()
并继续执行直到它返回时,您的函数不会等待。在函数返回并删除引用之前,无法保证工作线程将完成执行。
当你使worker
成为另一个类的成员时它起作用的原因是引用的生命周期现在与该类相关联。 import_data
返回时,引用计数不会减少。您的工作人员将持续存在,直到删除包含类,或者引用本身无效。
在moveToThread
中创建其他类中的worker是没有问题的,因为您只存储对该线程的引用。它并不代表线程实际运行的位置。