简体   繁体   中英

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?

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?

Maybe this is helping you:

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


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

    def create_window(self):
        self.windows.append(ChildWindow())

class ChildWindow(QMainWindow):
    def __init__(self, parent=None):
        super(ChildWindow, self).__init__(parent)
        self.show()

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

I used pyqt4 because i don't wanted to install pyside for that. I think that there are some diffrences in the qt-librarys on cross-plattforms, so that the linux application only allows one instance of the qapplication.

Here is a mailing list with the same problem => "PySide only supports creating a single persistent instance of QApplication. This singleton exists forever and cannot be deleted."

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM