Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 关于从QThread内部调用QThread外部方法的几个问题-我的设计有缺陷吗?_Python_Multithreading_Qt_Pyqt - Fatal编程技术网

Python 关于从QThread内部调用QThread外部方法的几个问题-我的设计有缺陷吗?

Python 关于从QThread内部调用QThread外部方法的几个问题-我的设计有缺陷吗?,python,multithreading,qt,pyqt,Python,Multithreading,Qt,Pyqt,我有一个应用程序,它有一个GUI线程和许多不同的工作线程。在这个应用程序中,我有一个functions.py模块,它包含许多不同的“实用”函数,这些函数在整个应用程序中都使用 昨天,应用程序已经发布,一些用户(少数,但仍然)报告了应用程序崩溃的问题。我查看了我的代码,发现了一个可能的设计缺陷,我想和SO的可爱的人们一起检查一下,看看我是否正确,这是否真的是一个缺陷 假设我在我的functions.py模块中定义了这个: class Functions: solveComputation

我有一个应用程序,它有一个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
变为真,请告诉我)。
solveAlternateCompution
是同一类中自动解决计算的另一个方法,但是,它也调用设置结果文本的
setResultText()
方法

第二个信号也会更新主GUI的状态栏文本

更糟糕的是,我认为上述设计虽然可能有缺陷,但不是问题所在

我相信,问题在于我调用这些方法的方式,它们来自工作线程(请注意,我有多个类似的工作线程,它们都是不同的“平台”)

假设我有这个(我有):

在本例中,我认为我的缺陷在于线程本身没有发出任何信号,而是直接调用驻留在该线程之外的可调用函数。我认为这会导致我的应用程序崩溃,对吗?尽管故障模块报告为QtGui4.dll

还有一件事:
函数
类中的这两个方法几乎同时被多个线程访问。这是否是明智的——多个线程是否可以同时访问驻留在线程外部的方法?我会不会“混淆”我的程序?我问这个问题的原因是,那些说应用程序没有崩溃的人报告说,
solveComputation()
经常返回不正确的文本——不是所有时间,而是经常返回。由于
COMPUTATION\u URL
的服务器可能需要一些时间来响应(甚至10秒以上),因此,一旦一个线程调用该方法,而
urllib
库仍在等待服务器响应,那么在这段时间内另一个线程可以调用它,导致它使用不同的
COMPUTATION\u URL
,这将导致它在某些情况下返回不正确的值

最后,我想到了解决方案:对于我的第一个(崩溃)问题,您认为正确的解决方案是直接从线程本身发出
信号,然后在GUI线程中连接它吗?这样做对吗

其次,对于返回不正确值的
solveComputation
,我是否会通过将该方法(以及伴随的方法)移动到每个
工作者
类来解决它?然后我可以直接给他们打电话,希望每个线程都有正确的响应——或者几十个不同的响应(因为我有那么多线程)——是吗

谢谢大家,我为文字墙道歉

编辑:我想补充一点,当在控制台中与一些用户一起运行时,会出现此错误
QObject:无法为位于不同线程中的父线程创建子线程。

(父线程为QLabel(0x4795500),父线程为QThread(0x2d3fd90),当前线程为WordpressCreator(0x49f0548)

如果您真的像这样使用
函数
类,将结果存储在类属性上,并在多个工作线程之间共享,那么您的设计就是有缺陷的。它应该使用所有实例方法,每个线程都应该使用此类的一个实例:

class Functions(QObject):

    solveComputationSignal = pyqtSignal(str)
    updateStatusSignal = pyqtSignal(int, str)

    def __init__(self, parent=None):
        super(Functions, self).__init__(parent)
        self.text = ""

    def setResultText(self, text):
        self.text = text


    def solveComputation(self, platform, computation, param=None):
        result = urllib.urlopen(COMPUTATION_URL).read()
        if param is None:
            self.solveComputationSignal.emit(result)
        else:
            self.solveAlternateComputation(platform, computation)

        while not self.text:
            time.sleep(3)

        return self.text if self.text else False


    def updateCurrentStatus(self, platform, statusText):
        self.updateStatusSignal.emit(platform, statusText)


# worker_A
    def run(self):
        ...
        f = Functions()
# worker_B
    def run(self):
        ...
        f = Functions()

另外,对于执行
urlopen
,您可以使用发出请求并在结果准备好时使用通知信号,而不是通过睡眠来检查结果是否准备就绪。

您正在使用具有类属性的classmethod来存储结果,并在线程之间共享该类。我可以看到c需要改进。是的。我知道它可以改进,但您愿意详细说明如何改进吗?更好的方法是什么?如果您的
函数
类需要将结果存储为成员,请不要使用classmethods。将它们都设为普通方法,并在
\uuuu init\uuuuu
中设置您的实例属性,否则每个工作人员都会共享这些方法s将损坏彼此的结果,对于您的编辑,您在线程中使用
QLabel
做什么。您正在创建它们吗?我已经修复了编辑-不知道如果QThread调用
sys.excepthook
(或任何其他方法),它将在该线程的上下文中调用它,而不是在定义它的线程中调用它(该线程是主GUI线程)。非常感谢您的回答。这可能是报告了如此多错误计算的原因,因为类变量被覆盖了-我没有想到。我的
函数
类还有许多其他类方法,我无法摆脱,因此我想是时候创建一个新类了,特别是针对t这些计算。类方法没有问题。你仍然可以用self从实例方法调用它们。关键是要知道数据何时共享。类方法适用于那些不需要唯一实例来操作的方法。它们不需要
class Functions(QObject):

    solveComputationSignal = pyqtSignal(str)
    updateStatusSignal = pyqtSignal(int, str)

    def __init__(self, parent=None):
        super(Functions, self).__init__(parent)
        self.text = ""

    def setResultText(self, text):
        self.text = text


    def solveComputation(self, platform, computation, param=None):
        result = urllib.urlopen(COMPUTATION_URL).read()
        if param is None:
            self.solveComputationSignal.emit(result)
        else:
            self.solveAlternateComputation(platform, computation)

        while not self.text:
            time.sleep(3)

        return self.text if self.text else False


    def updateCurrentStatus(self, platform, statusText):
        self.updateStatusSignal.emit(platform, statusText)


# worker_A
    def run(self):
        ...
        f = Functions()
# worker_B
    def run(self):
        ...
        f = Functions()