Есть ли способ подключиться к сигналу / слоту pyqt5 из мультипроцесса. Процесс на другом процессоре? - PullRequest
0 голосов
/ 22 февраля 2019

У меня есть архитектура, которая работает, но есть возможности для улучшения.Я ищу предложения по улучшению этой реализации.

  • Multiprocess.Process ()
    • Собирает последовательные данные и вызывает обратный вызов, который заполняет Manager.Queue ()
  • QThread ()
    • Собирает данные из Manager.Queue () и посылает сигнал через слот в Qthread ()
  • QtWidgets.QMainWindow ()
    • Подключает слотв обработчик данных для последовательных данных, который обновляет пользовательский интерфейс

Я хотел бы удалить Manager.Queue () и QThread ().Похоже, что это прыжки, чтобы прыгнуть, чтобы наладить многопроцессный обмен данными.

  • Я попытался устранить QThread (), пытаясь передать сигнал непосредственно из моей функции обратного вызова, выполняемой в multiprocess.Process ().
    • Сигнал, похоже, не попадает в слот.
    • Не уверен, как подключить его к обработчику.QObject ()?
      • Полагаю, это проблема незнания, как сделать эту игру приятной с GIL.

Мой поиск привел меня к этому безумию - Асинхронный шаблон в pyqt?Или более чистый фоновый режим вызова? Есть ли более простой способ?

Ниже приведен код, который демонстрирует то, что я пытаюсь улучшить -


    import multiprocessing
    import queue
    import sys
    import time

    from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QLabel, QVBoxLayout
    from PyQt5.QtGui import QIcon
    from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot

    def dataProducer(q):
        cnt = 0
        time.sleep(2)
        while True:
            print ("step 1 : producer %d" % cnt)
            q.put({ 'cnt' : cnt })
            cnt += 1
            time.sleep(1)

    class App(QMainWindow):
        sig_msg = pyqtSignal(object)  # this is the magic to send data to the gui

        def __init__(self, q):
            super().__init__()
            self.title = 'plumbing'
            self.left = 10
            self.top = 10
            self.width = 400
            self.height = 140
            self.q = q

            self.initUI()

        def initUI(self):
            self.setWindowTitle(self.title)
            self.setGeometry(self.left, self.top, self.width, self.height)

            self.consumerThread = QThread()
            self.sig_msg.connect(self.handleData) # connect signal to handler
            self.consumerThread.started.connect(self.dataConsumer) # connect QThread to slot
            self.consumerThread.start()

            self.show()

        def handleData(self, data):
            print ("step 3 : handler %s" % str(data))

        @pyqtSlot()
        def dataConsumer(self):
            while True:
                try:
                    data = self.q.get_nowait()
                except queue.Empty:
                    time.sleep(0.001) 
                    continue

                print ("step 2 : consumer %s" % str(data))
                self.sig_msg.emit(data) 


    if __name__ == '__main__':
        q = multiprocessing.Queue()
        p = multiprocessing.Process(target=dataProducer, args=(q,))
        p.start()

        app = QApplication(sys.argv)
        ex = App(q)
        sys.exit(app.exec_())


Вывод -

step 1 : producer 0
step 2 : consumer {'cnt': 0}
step 3 : handler {'cnt': 0}
step 1 : producer 1
step 2 : consumer {'cnt': 1}
step 3 : handler {'cnt': 1}
step 1 : producer 2
step 2 : consumer {'cnt': 2}
step 3 : handler {'cnt': 2}
step 1 : producer 3
step 2 : consumer {'cnt': 3}
step 3 : handler {'cnt': 3}
step 1 : producer 4
step 2 : consumer {'cnt': 4}
step 3 : handler {'cnt': 4}

Ближайший, который я смогЧтобы достичь этого, нужно передать сигнал в мой Process (), однако это требует от меня замены сторонней библиотеки, которую я должен постоянно обновлять.


    import multiprocessing
    import queue
    import sys
    import time

    from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QLabel, QVBoxLayout
    from PyQt5.QtGui import QIcon
    from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot

    def dataProducer(ex):
        cnt = 0
        time.sleep(2)
        while True:
            print ("step 1 : producer %d" % cnt)
            ex.sig_msg.emit({ 'cnt' : cnt })
            cnt += 1
            time.sleep(1)

    class App(QMainWindow):
        sig_msg = pyqtSignal(object)  # this is the magic to send data to the gui

        def __init__(self):
            super().__init__()
            self.title = 'plumbing'
            self.left = 10
            self.top = 10
            self.width = 400
            self.height = 140

            self.initUI()

        def initUI(self):
            self.setWindowTitle(self.title)
            self.setGeometry(self.left, self.top, self.width, self.height)

            self.sig_msg.connect(self.handleData) # connect signal to handler

            self.show()

        def handleData(self, data):
            print ("step 3 : handler %s" % str(data))

    if __name__ == '__main__':

        app = QApplication(sys.argv)
        ex = App()

        p = multiprocessing.Process(target=dataProducer, args=(ex,))
        p.start()

        sys.exit(app.exec_())



...