Многопроцессорность с Qt работает в Windows, но не в Linux

Я использую Qt для разработки приложений с графическим интерфейсом.

Я получаю сообщение об ошибке, когда пытаюсь создать еще один QApplication с помощью multiprocessing:

RuntimeError: Экземпляр QApplication уже существует

У меня есть главное окно, содержащее кнопку для запуска нового процесса, чтобы я мог создать новый экземпляр графического интерфейса. В основном так:

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_())

Он работает в Windows, но дает RuntimeError в Linux. Это из-за разницы в многопроцессорном механизме между Windows и Linux? Как я могу добиться того же в Linux?


person Northern    schedule 10.04.2015    source источник
comment
Что за ошибка полностью?   -  person Peter Wood    schedule 10.04.2015
comment
@PeterWood Ошибка в Linux: RuntimeError: A QApplication instance already exists. что означает, что Linux не создал тот же процесс, что и Windows. Новый процесс, созданный в Linux, может обнаружить приложение QApplication, работающее в моем основном процессе.   -  person Northern    schedule 10.04.2015
comment
вы используете ipython на linux?   -  person w5e    schedule 10.04.2015
comment
@Tweek Нет, но мне любопытно узнать, как это повлияет   -  person Northern    schedule 10.04.2015
comment
@NorthCat А как насчет deleteLater, это сработало? После app = QApplication(sys.argv) вы можете использовать app.aboutToQuit.connect(app.deleteLater)   -  person goGud    schedule 10.04.2015


Ответы (2)


Я понял после некоторого поиска многопроцессорной обработки python.

Дело в том, что в зависимости от платформы multiprocessing поддерживает разные способы запуска нового процесса. здесь есть очень хорошее объяснение. Итак, что происходит, так это то, что многопроцессорная обработка использует spawn в качестве метода по умолчанию в Windows, а использует fork в качестве метода по умолчанию в Linux. Различия:

порождать:

Родительский процесс запускает новый процесс интерпретатора Python. Дочерний процесс унаследует только те ресурсы, которые необходимы для запуска метода объектов процесса run(). В частности, ненужные файловые дескрипторы и дескрипторы родительского процесса не будут унаследованы.

вилка:

Родительский процесс использует os.fork() для разветвления интерпретатора Python. Дочерний процесс, когда он начинается, фактически идентичен родительскому процессу. Все ресурсы родителя наследуются дочерним процессом.

Таким образом, я пришел к простому решению:

добавить multiprocessing.set_start_method('spawn') ниже if __name__=="__main__":.

set_start_method() появился в версии 3.4. Здорово, что это обновление! Я не уверен, как установить этот параметр в предыдущих версиях. Кто-нибудь знает?

person Northern    schedule 10.04.2015

Возможно, это поможет вам:

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_())

Я использовал pyqt4, потому что не хотел устанавливать для этого pyside. Я думаю, что есть некоторые различия в qt-библиотеках на кроссплатформенных платформах, так что приложение linux допускает только один экземпляр qapplication.

Вот список рассылки с той же проблемой => «PySide поддерживает только создание одного постоянного экземпляра QApplication. Этот синглтон существует вечно и не может быть удален».

person w5e    schedule 10.04.2015