使用 Pyside2 QThread 线程化时,Scipy curve_fit 崩溃

Posted

技术标签:

【中文标题】使用 Pyside2 QThread 线程化时,Scipy curve_fit 崩溃【英文标题】:Scipy curve_fit crashes when threaded with Pyside2 QThread 【发布时间】:2020-11-17 10:20:03 【问题描述】:

我正在使用 pyside2 制作一个 QT5 应用程序,我在其中使用 scipy.optimize.curve_fit 拟合数千个函数。为了避免冻结 gui,我使用 Qthread() 将这数千个对 curve_fit 的调用放在单独的线程上。 有时这可行,但如果我反复运行这个程序,它偶尔会在调用 curve_fit 时崩溃。

我创建了一个可以重现此错误的最小示例。有时我必须运行它 20 次才能崩溃。错误是:“分段错误:11”和“进程以退出代码 139 完成(被信号 11 中断:SIGSEGV)”

我使用的是 Python 3.8.2,所有库都已更新。

import sys
from PySide2.QtWidgets import QApplication, QLabel, QMainWindow
from PySide2.QtCore import Qt, QThread, QObject, Signal
import numpy as np
from scipy.optimize import curve_fit

class ProcessData(QObject):
    loaded = Signal(int)
    ready = Signal(list)
    finished = Signal()

    def __init__(self, data):
        super().__init__()
        self._data = data

    def func(self, x, a, b, c):
        return a * np.exp(-b * x) + c

    def run(self):
        result = []
        y = self.func(self._data, 2.5, 1.3, 0.5)
        for i in range(1000):
            y_noise = 0.2 * np.random.normal(size=self._data.size)
            ydata = y + y_noise
            print("start fit: ".format(i))
            popt, pcov = curve_fit(self.func, self._data, ydata)
            print("finished fit: ".format(i))
            result.append(popt)
        self.ready.emit(result)
        self.finished.emit()

    def stop(self):
        self._stop = True

class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setWindowTitle("Test Application")
        self.thread = QThread()
        self.data = np.linspace(0, 4, 50)
        self.process_data = ProcessData(self.data)
        self.process_data.moveToThread(self.thread)
        self.process_data.ready.connect(self.show_result)
        self.process_data.finished.connect(self.thread.quit)
        self.thread.started.connect(self.process_data.run)
        self.thread.finished.connect(self.process_data.deleteLater)
        self.thread.start()

    def show_result(self, result):
        label = QLabel("Fitted  functions".format(len(result)))
        label.setAlignment(Qt.AlignCenter)
        self.setCentralWidget(label)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

【问题讨论】:

我没有在 Linux 上使用 PySide2 5.15.1 重现该问题 我在 Mac 上使用 python 3.8.2,numpy 1.19.4,scipy 1.5.4,Pyside2 5.15.1 【参考方案1】:

免责声明:我无法重现该问题。

据我所知scipy.optimize.curve_fit 在后台使用scipy.optimize.leastsq,这不是线程安全的,您应该在调用curve_fit 之前获取线程锁(但是它可能会破坏您的目的)。分段错误也是内存管理出现问题的标志,可能读取了未在进程中映射的数据。您可以尝试多处理,但我认为这不会有更好的效果(因为您正在制作 GUI)。

【讨论】:

以上是关于使用 Pyside2 QThread 线程化时,Scipy curve_fit 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 QThread 进行子线程之间的数据传输?

PySide2 QThread 正在冻结 UI

访问在QThread内部由Pynput侦听器调用的线程中访问的SQLite3数据库连接时关注竞争条件

关注在 QThread 内由 Pynput 侦听器调用的线程中访问的 SQLite3 数据库连接时的竞争条件

PySide2 使用 QProgressBar 作为信号参数

无法使用 QMutex 锁定变量