我有一个具有 GUI 线程和许多不同工作线程的应用程序。在这个应用程序中,我有一个functions.py
模块,其中包含许多在整个应用程序中使用的不同“实用程序”功能。
昨天应用程序已经发布,一些用户(少数,但仍然)报告了应用程序崩溃的问题。我查看了我的代码并发现了一个可能的设计缺陷,并想与 SO 的可爱人员核实一下,看看我是否正确,这是否确实是一个缺陷。
假设我在我的functions.py
模块中定义了这个:
class Functions:
solveComputationSignal = Signal(str)
updateStatusSignal = Signal(int, str)
text = None
@classmethod
def setResultText(self, text):
self.text = text
@classmethod
def solveComputation(cls, platform, computation, param=None):
#Not the entirety of the method is listed here
result = urllib.urlopen(COMPUTATION_URL).read()
if param is None:
cls.solveComputationSignal.emit(result)
else:
cls.solveAlternateComputation(platform, computation)
while not self.text:
time.sleep(3)
return self.text if self.text else False
@classmethod
def updateCurrentStatus(cls, platform, statusText):
cls.updateStatusSignal.emit(platform, statusText)
我认为这些方法本身就很好。此处定义的两个信号在 GUI 线程中连接。第一个信号弹出一个对话框,其中显示了计算。GUI线程调用该setResultText()
方法并设置用户输入的结果字符串(如果有人知道更好的方法来等待用户输入文本,而不是睡眠并等待self.text
变为True,请告诉我)。这solveAlternateComputation
是同一类中的另一种自动解决计算的方法,但是,它也调用setResultText()
设置结果文本的方法。
第二个信号也更新主 GUI 的状态栏文本。
更糟糕的是,我认为上述设计虽然可能存在缺陷,但并不是问题所在。
我相信问题在于我调用这些方法的方式,它来自工作线程(请注意,我有多个类似的工作人员,所有这些都是不同的“平台”)
假设我有这个(我有):
class WorkerPlatform1(QThread):
#Init and other methods are here
def run(self):
#Thread does its job here, but then when it needs to present the
#computation, instead of emitting a signal, this is what I do
self.f = functions.Functions
result = self.f.solveComputation(platform, computation)
if result:
#Go on with the task
else:
self.f.updateCurrentStatus(platform, "Error grabbing computation!")
在这种情况下,我认为我的缺陷是线程本身没有发出任何信号,而是直接调用驻留在该线程之外的可调用对象。我是否认为这可能导致我的应用程序崩溃?虽然故障模块报告为QtGui4.dll
还有一件事:Functions
类中的这两种方法几乎同时被许多线程访问。这甚至是可取的 - 让许多线程同时访问驻留在线程之外的方法吗?我会“混淆”我的程序吗?我问的原因是因为那些说应用程序没有崩溃的人报告说,经常solveComputation()
返回不正确的文本 - 不是一直,而是经常。由于该COMPUTATION_URL
服务器可能需要一些时间来响应(甚至超过 10 秒),是否有可能,一旦一个线程调用该方法,而urllib
库仍在等待服务器响应,那么另一个线程可以调用它,导致它使用不同的COMPUTATION_URL
,这会导致它在某些情况下返回不正确的值?
最后,我正在考虑解决方案:对于我的第一个(崩溃)问题,您认为正确的解决方案是直接Signal
从线程本身发出 a,然后在 GUI 线程中连接它吗?这是正确的方法吗?
其次,对于solveComputation
返回不正确的值,我会通过将该方法(和随附的方法)移动到每个Worker
类来解决它吗?那么我可以直接给他们打电话,并希望每个线程都有正确的响应——或者,几十个不同的响应(因为我有那么多线程)?
谢谢大家,我为文字墙道歉。
编辑:我想补充一点,当与某些用户在控制台中运行时,会出现此错误QObject: Cannot create children for a parent that is in a different thread.
(Parent is QLabel(0x4795500), parent's thread is QThread(0x2d3fd90), current thread is WordpressCreator(0x49f0548)