multiprocessing and GUI updating - Qprocess or multiprocessing?
multiprocessing, multithreading, python, qt, user-interface
Solution
`QProcess` is for reading and writing to pipes (shell/cmd). Use one of these.
- Create a class with worker function and run it as thread by `QtConcurrent.run(object, method, args)`
- connect `QTimer.timeout()` with your worker function.
Problem
After reading the literature on QProcesses and the multiprocessing module for python, I am still having trouble creating a working and responsive GUI throughout having large processes ongoing in the background. So far, I have come up with this simplified version of my application, which still shows similar problems to what many have described. ``` from PyQt4 import QtCore, QtGui import multiprocessing as mp import numpy as np import sys class Spectra: def __init__(self, spectra_name, X, Y): self.spectra_name = spectra_name self.X = X self.Y = Y self.iteration = 0 def complex_processing_on_spectra(self, pipe_conn): self.iteration += 1 pipe_conn.send(self.iteration) class Spectra_Tab(QtGui.QTabWidget): def __init__(self, parent, spectra): self.parent = parent self.spectra = spectra QtGui.QTabWidget.__init__(self, parent) self.treeWidget = QtGui.QTreeWidget(self) self.properties = QtGui.QTreeWidgetItem(self.treeWidget, ["Properties"]) self.step = QtGui.QTreeWidgetItem(self.properties, ["Iteration #"]) self.consumer, self.producer = mp.Pipe() # Make process associated with tab self.process = mp.Process(target=self.spectra.complex_processing_on_spectra, args=(self.producer,)) def update_GUI(self, iteration): self.step.setText(1, str(iteration)) def start_computation(self): self.process.start() while(True): message = self.consumer.recv() if message == 'done': break self.update_GUI(message) self.process.join() return class MainWindow(QtGui.QMainWindow): def __init__(self, parent = None): QtGui.QMainWindow.__init__(self) self.setTabShape(QtGui.QTabWidget.Rounded) self.centralwidget = QtGui.QWidget(self) self.top_level_layout = QtGui.QGridLayout(self.centralwidget) self.tabWidget = QtGui.QTabWidget(self.centralwidget) self.top_level_layout.addWidget(self.tabWidget, 1, 0, 25, 25) process_button = QtGui.QPushButton("Process") self.top_level_layout.addWidget(process_button, 0, 1) QtCore.QObject.connect(process_button, QtCore.SIGNAL("clicked()"), self.process) self.setCentralWidget(self.centralwidget) self.centralwidget.setLayout(self.top_level_layout) # Open several files in loop from button - simplifed to one here X = np.arange(0.1200,.2) Y = np.arange(0.1200,.2) self.spectra = Spectra('name', X, Y) self.spectra_tab = Spectra_Tab(self.tabWidget, self.spectra) self.tabWidget.addTab(self.spectra_tab, 'name') def process(self): self.spectra_tab.start_computation() return if __name__ == "__main__": app = QtGui.QApplication([]) win = MainWindow() win.show() sys.exit(app.exec_()) ``` This should be fully capable of executing if you have the dependencies. At the moment I have a QThreaded version of my program which works with signals and slots; Hwoever, I think it is important to have the ability to use all of a computers processors, since most users have ~8 cores available to them. So, I would like to expand this signal/slot threaded approach to the multiprocessed version using `multiprocessing` or `QProcess`es. Does anyone have suggestions for whether or not to use `QProcess` or `multiprocessing`? While they are both complicated to me, QProcess seems as though it has less forums of people using pyQt, So I went with multiprocessing. Would it be simpler to go with QProcess since I already have signals/slots working with threads? EDIT: Should I add a class like this as suggested? ``` class My_Process(QtCore.QProcess): def __init__(self, spectra): QtCore.QProcess.__init__(self) self.spectra = spectra def worker(self): QtConcurrent.run(self.spectra, self.spectra.complex_processing_on_spectra) def run(self): QtCore.QObject.connect(self, QtCore.SIGNAL(QTimer.timeout()), self.worker) ```