2

我对 python 比较陌生,但能够运行一个相当有用的程序来处理大量数据。我可以使用另一个 python 脚本顺序地在多组数据上运行它以串行调用程序,但我想创建一个 GUI 并使用多线程来允许其他人在不了解编程的所有细节的情况下使用它。我成功创建了 GUI,并且可以使用信号和插槽双向馈送数据。我遇到的问题是创建具有相同功能的多个线程。

我做了一些研究,似乎该函数需要是线程安全的,不幸的是我的不是因为我使用的是来自 scipy 的curve_fit(),它不是线程安全的。所以,根据我在这个论坛和其他人的阅读,我应该使用 mutex.lock(),但是在调用 curve_fit() 时我得到“SystemError: null argument to internal routine”

这是一些示例代码来演示我所做的事情:

    import sip
    sip.setapi('QString', 2)

    import sys, time
    from PyQt5 import QtCore, QtGui, uic, QtWidgets
    from ZthCalculation import ZthObject

    qtCreatorFile = "PyQtZthUI_01.ui" # Enter file here.

    Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)

    #class MyApp(QtGui.QMainWindow, Ui_MainWindow):
    class MyApp(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self):
            super(self.__class__, self).__init__()
            QtWidgets.QMainWindow.__init__(self)
            Ui_MainWindow.__init__(self)
            self.setupUi(self)
            self.RunButton.clicked.connect(self.RunZthTest)
    .
    .
    .
        def RunZthTest(self):
  #create as processes instead of threads???
  #            self.Process1 = QtCore.QProcess()
            self.Thread1 = QtCore.QThread()
            self.obj1 = ZthObject(self.InputWet1.text(), self.InputDry1.text(), self.Output1.text(), self.side1)
            self.obj1.moveToThread(self.Thread1)
            self.Thread1.started.connect(self.obj1.ZthCalculation)
            self.obj1.textBox.connect(self.updateTextBox1)
            self.signal1 = self.obj1.finished.connect(self.Thread1.quit)
            self.Thread1.setObjectName("Thread1")
            self.Thread1.start()
            time.sleep(.1)

            self.Thread2 = QtCore.QThread()
            self.obj2 = ZthObject(self.InputWet2.text(), self.InputDry2.text(), self.Output2.text(), self.side2)
            self.obj2.moveToThread(self.Thread2)
            self.Thread2.started.connect(self.obj2.ZthCalculation)
            self.obj2.textBox.connect(self.updateTextBox2)
            self.signal2 = self.obj2.finished.connect(self.Thread2.quit)
            self.Thread2.setObjectName("Thread2")
            self.Thread2.start()
            time.sleep(.1)

            self.Thread3 = QtCore.QThread()
            self.obj3 = ZthObject(self.InputWet3.text(), self.InputDry3.text(), self.Output3.text(), self.side3)
            self.obj3.moveToThread(self.Thread3)
            self.Thread3.started.connect(self.obj3.ZthCalculation)
            self.obj3.textBox.connect(self.updateTextBox3)
            self.signal3 = self.obj3.finished.connect(self.Thread3.quit)
            self.Thread3.setObjectName("Thread3")
            self.Thread3.start()
    .
    .
    .

    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        window = MyApp()
        window.show()
    #    sys.exit(app.exec_())
        app.exec_()

在另一个文件中,我有作为线程调用的主函数:

class ZthObject(QtCore.QObject):
    killthread = False
    finished = QtCore.pyqtSignal()
    textBox = QtCore.pyqtSignal(str)
    def __init__(self, wetFilePath, dryFilePath, outFilePath, side, parent=None):
        super(self.__class__, self).__init__()
        self.wetFilePath = wetFilePath
        self.dryFilePath = dryFilePath
        self.outFilePath = outFilePath
        self.side = side
        self.mutex = QtCore.QMutex()
    def cleanup(self):
        ZthObject.killthread = True

#    def ZthCalculation(self, wetFilePath, dryFilePath, outFilePath, side):
    def ZthCalculation(self):
        #calculations here
.
.
.
        print("waypoint2")
        self.mutex.lock()
        popt, pcov = curve_fit(Foster6, timeShort, ZthjcShort, p0 = [Rs, taus])
        self.mutex.unlock()
.
.
.
        self.finished.emit()

我可以成功运行只调用一个线程的代码,但是如果我调用多个线程,那么输出窗口会为每个调用的线程打印出“waypoint2”,然后崩溃并出现我上面提到的系统错误。

我究竟做错了什么?我是否需要使用单独的进程而不是 Qthreads?我误解了线程是如何工作的吗?我希望它们在独立变量空间中运行。

4

1 回答 1

2

如果共享函数内部的所有其他东西也都尊重互斥锁,那么使用互斥锁实际上只会使线程安全。在这种情况下,它不会,因为虽然使用互斥锁可以防止同时curve_fit调用在另一个线程(例如主线程)中同时使用线程不安全的代码。

再加上 Python GIL 阻止了真正的线程处理(如果您的任务是 IO 限制而不是 CPU 限制,线程只在 Python 中提供速度提升),我建议转向多进程模型。

于 2017-01-28T05:10:16.123 回答