今天在进行pyqt编写多线程时,遇到了这个错误:Process finished with exit code -1073740791 (0xC0000409),产生这个错误的原因一般是在线程的run函数运行出错。
下面介绍下我要处理的问题:
在窗体上读取一些数据,然后点击按钮后通过多线程模块QThread去计算,然后再把计算的结果传给界面进行显示。
之所以使用多线程就是因为运算时间较长,会导致窗体假死,所以为了避免这个问题,使用了多线程。
具体的代码如下:
# 我创建的QThread类
class ThreadCalFdem(QThread):
# 自定义信号对象,参数ForwardResult就代表这个信号可以传一个ForwardResult类的对象
trigger = pyqtSignal(ForwardResult)
def __init__(self):
super(ThreadCalFdem, self).__init__()
self.detector = None
self.target = None
def run(self):
self.forward_result = simulate(self.target, self.detector) # simulate是计算的函数
self.trigger.emit(self.forward_result) # 将计算的结果作为信号进行发送,forward_result是ForwardResult的实例
然后我在Mainwindow类里面,调用我建立的多线程类,如下:
class MainWindow(QMainWindow, Ui_MainWindow):
#定义的正向计算的函数
def run_forward_calculate(self):
# 主要就是创建多线程类,并进行正向计算,然后将多线程返回的结果传给run_forward_result_process函数进行显示
thread_cal_fdem = ThreadCalFdem()
thread_cal_fdem.target = self.target
thread_cal_fdem.detector = self.detector
thread_cal_fdem.start()
# run_forward_result_process是slots函数,此处将信号与槽函数进行连接,做出响应
thread_cal_fdem.trigger.connect(self.run_forward_result_process)
pass
# 对正向计算的结果处理的函数
def run_forward_result_process(self, forward_result):
# 主要是对forward_result进行显示的操作
pass
# 按钮点击时间触发run_forward_calculate函数
self.pb_run_forward_simulation.clicked.connect(self.run_forward_calculate)
对于上面这种场景当我运行时就出现了这个bug,当我点击调试的时候,发现,并没有错误,但是如果直接运行就会有错误。
那问题到底出现在哪?我目前搞明白了会出现错误的原因,但是我没有搞明白为什么调试的时候没有错误的原因。
出现错误的主要原因就是由于我定义的thread_cal_fdem是一个局部变量,当其所在方法运行结束的时候,它的生命周期也就结束了,但是这个线程里的程序很有可能还没有运行完!所以可能会报错。
具体解释下就是由于我是在一个函数里面定义的线程,当这个函数跑完了,实际上此时这个线程的生命周期也就结束了,而此时线程里面的run方法的计算仍然没有计算完,所以会出现错误。
那么该如何修改呢,直接将该线程定义在MainWindow的属性里面,因为MainWindow的生命周期是在整个窗体运行的期间,所以就不用担心线程生命周期结束了,而线程的计算还没有结束这种情况。如下:
class MainWindow(QMainWindow, Ui_MainWindow):
#定义的正向计算的函数
def run_forward_calculate(self):
# 主要就是创建多线程类,并进行正向计算,然后将多线程返回的结果传给run_forward_result_process函数进行显示
self.thread_cal_fdem = ThreadCalFdem()
self.thread_cal_fdem.target = self.target
self.thread_cal_fdem.detector = self.detector
self.thread_cal_fdem.start()
self.thread_cal_fdem.trigger.connect(self.run_forward_result_process)
pass
# 对正向计算的结果处理的函数
def run_forward_result_process(self, forward_result):
# 主要是对forward_result进行显示的操作
pass
# 按钮点击时间触发run_forward_calculate函数
self.pb_run_forward_simulation.clicked.connect(self.run_forward_calculate)
关于pyqt中多线程传递返回值的问题,我上面利用的是信号去传递返回值,但是对于pandas.DataFrame等数据 ,信号不能传递这类数据,那么怎么处理呢?我目前想到的方法就是在多线程类里面建立获取返回值的函数,同样利用信号传递线程计算的函数计算结束的标志,比如传递一个int类型的数据,1表示计算过程正常结束。当接收到这样的信号后在通过多线程的实例调用获取返回值的函数,此时该函数返回的结果就是多线程中计算结束的结果。如果不通过信号去返回一个值标志计算结束,直接调用获取返回值的函数,这是不可以的,因为当调用这个函数的时候无法确定多线程中计算的程序计算结束了。
对于上面的程序利用这种方式改写的结果如下:
# 我创建的QThread类
class ThreadCalFdem(QThread):
# 自定义信号对象,参数ForwardResult就代表这个信号可以传一个ForwardResult类的对象
forward_result = None
trigger = pyqtSignal(int)
def __init__(self):
super(ThreadCalFdem, self).__init__()
self.detector = None
self.target = None
def run(self):
self.forward_result = simulate(self.target, self.detector) # simulate是计算的函数
self.trigger.emit(1) # 将计算的结果传给定义的信号,forward_result是ForwardResult的实例
@property
def forward_result(self):
return self.forward_result
class MainWindow(QMainWindow, Ui_MainWindow):
#定义的正向计算的函数
def run_forward_calculate(self):
# 主要就是创建多线程类,并进行正向计算,然后将多线程返回的结果传给run_forward_result_process函数进行显示
self.thread_cal_fdem = ThreadCalFdem()
self.thread_cal_fdem.target = self.target
self.thread_cal_fdem.detector = self.detector
self.thread_cal_fdem.start()
self.thread_cal_fdem.trigger.connect(self.run_forward_result_process)
pass
# 对正向计算的结果处理的函数
def run_forward_result_process(self, flag):
# 主要是对forward_result进行显示的操作
if 1 == flag:
self.thread_cal_fdem.forward_result # 得到多线程返回的结果
pass
# 按钮点击时间触发run_forward_calculate函数
self.pb_run_forward_simulation.clicked.connect(self.run_forward_calculate)
更:
上面关于多线程传值的问题,其实用信号传值的时候,虽然信号只可以直接传递python内置数据类型的值,无法直接传递pandas.DataFrame等数据,但是可以把其封装到python内置数据类型当中,比如用一个元组去放pandas.DataFrame等数据,然后就可以用信号传值了。
相关参考文献:
https://blog.csdn.net/wuwei_201/article/details/104720386 pyqt5 的多线程(QThread)遇到的坑(一)
https://www.cnblogs.com/linyfeng/p/12239856.html PyQt5中多线程模块QThread使用方法
https://doc.qt.io/qt-5/thread-basics.html qt官网讲多线程讲的比较好的
https://blog.csdn.net/qq_37174526/article/details/92414970 其他获取多线程返回值的方式