是否可以通过multiprocess.Process连接到另一个CPU上的py​​qt5信号/插槽?

时间:2019-02-22 02:19:34

标签: python signals pyqt5 qthread slot

我有一个可行的体系结构,但仍有改进的空间。 我正在寻找有关改进此实现的建议。

  • Multiprocess.Process()
    • 收集串行数据并调用填充Manager.Queue()的回调
  • QThread()
    • 从Manager.Queue()收集数据并通过Qthread()中的插槽发出信号
  • QtWidgets.QMainWindow()
    • 将插槽连接到用于串行数据的数据处理程序,该数据处理程序将更新UI

我想消除Manager.Queue()和QThread()。这些似乎使人们无法通过多进程数据交换。

  • 我试图通过尝试直接从在multiprocess.Process()中执行的回调函数中发出信号来消除QThread()。
    • 信号似乎无法到达插槽。
    • 不确定如何将其连接到处理程序。 QObject()?
      • 我认为这是一个不知道如何使GIL发挥出色的问题。

我的搜索使我陷入了这种疯狂- Async like pattern in pyqt? Or cleaner background call pattern? 有更容易的方法吗 ?

以下是演示我要改进的代码-


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



0 个答案:

没有答案