У меня есть архитектура, которая работает, но есть возможности для улучшения.Я ищу предложения по улучшению этой реализации.
- 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_())