如何重构此代码,以便不发生Pickle'缓冲区'错误

时间:2013-02-06 18:31:38

标签: python multithreading qt user-interface matplotlib

我想知道是否有人对我目前的酸洗错误有任何好的解决方案。我正在尝试将我的代码设置为并行打开几个不同的进程,每个进程都有一个适合的进程,可以在matplotlib画布上实时显示。在我的主应用程序中,我有一个激活此功能的按钮:

def process_data(self):
        process_list = []
        for tab in self.tab_list:
            process_list.append(mp.Process(target=process_and_fit, args=(tab,)))
            process_list[-1].start()
            process_list[-1].join()
        return

正如您可能注意到的那样,'tab'(PyQt4.QtGui.QTabWidget对象)被传递给函数process_and_fit,我注意到它不能被轻易腌制(link here)。 但是,我不确定如何更改代码以摆脱传递的帧,因为它需要间接地在process_and_fit函数中调用。通过间接我的意思是这样的:(再次伪造代码)

def process_and_fit(tab): # this just sets up and starts the fitting process
        result = lmfit.Minimizer(residual, parameters, fcn_args=(tab,))
        result.prepare_fit()
        result.leastsq()

def residual(params, tab):
    residual_array = Y - model
    tab.refreshFigure()
    return residual_array

class tab(QtGui.QTabWidget):
    def __init__(self, parent, spectra):
       # stuff to initialize the tab widget and hold all of the matplotlib lines and canvases

    # This just refreshes the GUI stuff everytime that the parameters are fit in the least squares method
    def refreshFigure(self):     
        self.line.set_data(self.spectra.X, self.spectra.model)
        self.plot.draw_artist(self.line)
        self.plot.figure.canvas.blit(self.plot.bbox)

有没有人知道如何解决这个酸洗错误,因为与进程关联的选项卡应该只有一组与之关联的数据?我看了Steven Bethard's方法,但我真的不明白在哪里放置代码或如何使用它。 (我是化学工程师,不是计算机科学家,所以有很多我不理解的事情)

非常感谢任何帮助。

编辑:我根据要求添加了忘记的链接。

1 个答案:

答案 0 :(得分:2)

主要问题是,您无法从主UI线程(所有Qt调用所在的线程)中的单独进程进行UI更改。您需要使用mp.Pipemp.Queue与主进程进行通信。

def process_data(self):
    for tab in self.tab_list:
        consumer, producer = mp.Pipe()
        process_list.append(mp.Process(target=process_and_fit, args=(producer,)))
        process_list[-1].start()
        while (true):
            message = consumer.recv()  # blocks
            if message == 'done':
                break
            # tab.spectra.X, tab.spectra.model = message
            tab.refreshFigure()
        process_list[-1].join()
    return

def process_and_fit(pipe_conn):
    ...
    pipe_conn.send('done')

def residual(params, pipe_conn):
    residual_array = Y - model
    pipe_conn.send('refresh')  # or replace 'refresh' with (X, model)
    return residual_array

还有一点需要注意:阻止consumer.recv()可能会挂起GUI线程。有足够的资源来缓解这个问题,“subprocess Popen blocking PyQt GUI”这个问题会有所帮助,因为你应该切换到QThread。 (Qthread:PySidePyQt

使用QThreads代替Python线程的优点在于QThreads,因为你已经在Qt的主事件循环中,你可以使用异步(非阻塞)回调来更新UI。