Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiprocessing with Qt works in windows but not linux

I am using Qt for developing GUI applications.

I get an error when I try to create another QApplication using multiprocessing:

RuntimeError: A QApplication instance already exists

I have a main window, which contains a button for spawning a new process so that I can create a new GUI instance. Basically like this:

from PySide.QtCore import *
from PySide.QtGui import *
import multiprocessing
import sys


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        btn = QPushButton('run new instance')
        btn.clicked.connect(self.create_daemon)
        self.setCentralWidget(btn)

    def create_daemon(self):
        p = multiprocessing.Process(target=new_window)
        p.start()

def new_window():
    app=QApplication(sys.argv)
    ex = MainWindow()
    ex.show()
    sys.exit(app.exec_())

if __name__=="__main__":
    app=QApplication(sys.argv)
    ex = MainWindow()
    ex.show()
    sys.exit(app.exec_())

It works in Windows but gives the RuntimeError in Linux. Is this because of difference in multiprocessing mechanism between Windows and Linux? How could I achieve the same thing in Linux?

like image 679
Northern Avatar asked Apr 10 '15 08:04

Northern


1 Answers

I figured out after some googling of python multiprocessing.

The point is, depends on the platform multiprocessing supports different ways to start a new process. There is a very good explanation here. So, what happens is that multiprocessing use spawn as the default method in Windows, while use fork as the default method in Linux. The Difference:

spawn:

The parent process starts a fresh python interpreter process. The child process will only inherit those resources necessary to run the process objects run() method. In particular, unnecessary file descriptors and handles from the parent process will not be inherited.

fork:

The parent process uses os.fork() to fork the Python interpreter. The child process, when it begins, is effectively identical to the parent process. All resources of the parent are inherited by the child process.

Thus, I came to a simple solution:

add multiprocessing.set_start_method('spawn') bellow if __name__=="__main__":.

set_start_method() is new in version 3.4. Great to have this update! I am not sure how to set this parameter in previous versions. Anyone knows?

like image 69
Northern Avatar answered Oct 21 '22 13:10

Northern