Reputation: 3782
I have a program which uses QThreads and Signals/Slots to communicate to a GUI. It has the simplified form shown below.
However, I would like to change this to a QProcess so that I can take advantage of multicore processing. Is there a simple way to do this?
If I simply change QThread
to QProcess
, there is no moveToThread()
function for processes. I have been trying several different approaches to multicore processing, such as Pipes()
and Queues()
in the multiprocessing
module, but I can't get anything to work very well. So, I figured it would be easier to use QProcess
since I am already in Qtland.
Here is the simplified code I have for QThreads
, signals and slots.
from PyQt4 import QtCore, QtGui
import multiprocessing as mp
import numpy as np
import sys
class Spectra(QtCore.QObject):
update_signal = QtCore.pyqtSignal(str)
done_signal = QtCore.pyqtSignal()
def __init__(self, spectra_name, X, Y):
QtCore.QObject.__init__(self)
self.spectra_name = spectra_name
self.X = X
self.Y = Y
self.iteration = 0
@QtCore.pyqtSlot()
def complex_processing_on_spectra(self):
for i in range(0,99999):
self.iteration += 1
self.update_signal.emit(str(self.iteration))
self.done_signal.emit()
class Spectra_Tab(QtGui.QTabWidget):
start_comp = QtCore.pyqtSignal()
kill_thread = QtCore.pyqtSignal()
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 #"])
thread = QtCore.QThread(parent=self)
self.worker = self.spectra
self.worker.moveToThread(thread)
self.worker.update_signal.connect(self.update_GUI)
self.worker.done_signal.connect(self.closeEvent)
self.start_comp.connect(self.worker.complex_processing_on_spectra)
self.kill_thread.connect(thread.quit)
thread.start()
@QtCore.pyqtSlot(str)
def update_GUI(self, iteration):
self.step.setText(0, iteration)
def start_computation(self):
self.start_comp.emit()
def closeEvent(self):
print 'done with processing'
self.kill_thread.emit()
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_())
Upvotes: 1
Views: 1675
Reputation: 5345
There is no moveToThread()
for processes since a process lives in its own memory space, so it cannot see MainWindow
or any of it members. The application that you start using QProcess
should be able to execute as stand-alone application.
To run spectra in another QProcess
, you will need to make spectra a separate executable module instead of MainWindow member as it is now.
EDIT:
You need to define the self-contained module that is least dependent on the MainWindow
- it can be spectra process only, or spectra process with tab. You can pass info to process either on construction, or through standard input, and retrieve data from process through standard output. Key idea when selecting lawyer to put process in is to minimize communication and dependency between the process and MainWindow. You may think of a process as simple C program:
int main(int argc,char* argv[]);
you can pass arguments on startup, get additional input from MainWindow through cin/stdin if necessary, output some results to MainWindow
through cout/stdout/stderr (QProcess
have interface for that).
Upvotes: 2