Basierend auf den in anderen Antworten erwähnten Worker-Objektmethoden habe ich mich entschlossen, zu prüfen, ob ich die Lösung erweitern kann, um mehr Threads aufzurufen - in diesem Fall die optimale Anzahl, die die Maschine ausführen und mehrere Worker mit unbestimmten Abschlusszeiten hochfahren kann. Dazu muss ich noch QThread unterordnen - aber nur, um eine Thread-Nummer zuzuweisen und die Signale "beendet" und "gestartet" neu zu implementieren, um ihre Thread-Nummer einzuschließen.
Ich habe mich ziemlich auf die Signale zwischen der Haupt-GUI, den Threads und den Arbeitern konzentriert.
In ähnlicher Weise war es schwierig, andere Antworten darauf hinzuweisen, dass der QThread nicht erzogen wurde, aber ich denke nicht, dass dies ein echtes Problem ist. Mein Code achtet jedoch auch darauf, die QThread-Objekte zu zerstören.
Die Worker-Objekte konnten jedoch nicht übergeordnet werden, sodass es wünschenswert erscheint, ihnen das deleteLater () -Signal zu senden, entweder wenn die Thread-Funktion beendet oder die GUI zerstört ist. Ich habe meinen eigenen Code hängen lassen, weil ich das nicht getan habe.
Eine weitere Verbesserung, die ich für notwendig hielt, war die Neuimplementierung des closeEvent der GUI (QWidget), sodass die Threads zum Beenden aufgefordert wurden und die GUI dann warten musste, bis alle Threads fertig waren. Als ich mit einigen anderen Antworten auf diese Frage spielte, bekam ich QThread zerstörte Fehler.
Vielleicht ist es für andere nützlich. Ich fand es auf jeden Fall eine nützliche Übung. Vielleicht kennen andere einen besseren Weg, wie ein Thread seine Identität ankündigen kann.
import sys
from PyQt4.QtCore import QThread, pyqtSlot, pyqtSignal
from PyQt4.QtGui import QApplication, QLabel, QWidget, QGridLayout
import sys
import worker
class Thread(QThread):
startedx = pyqtSignal(int)
finishedx = pyqtSignal(int)
def __init__(self,i,parent=None):
super().__init__(parent)
self.idd = i
self.started.connect(self.starttt)
self.finished.connect(self.finisheddd)
@pyqtSlot()
def starttt(self):
print('started signal from thread emitted')
self.startedx.emit(self.idd)
@pyqtSlot()
def finisheddd(self):
print('finished signal from thread emitted')
self.finishedx.emit(self.idd)
class Form(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.worker={}
self.threadx={}
self.i=0
i=0
self.threadtest = QThread(self)
self.idealthreadcount = self.threadtest.idealThreadCount()
print("This machine can handle {} threads optimally".format(self.idealthreadcount))
while i <self.idealthreadcount:
self.setupThread(i)
i+=1
i=0
while i<self.idealthreadcount:
self.startThread(i)
i+=1
print("Main Gui running in thread {}.".format(self.thread()))
def setupThread(self,i):
self.worker[i]= worker.Worker(i)
self.threadx[i] = Thread(i,parent=self)
self.threadx[i].setObjectName("python thread{}"+str(i))
self.threadx[i].startedx.connect(self.threadStarted)
self.threadx[i].finishedx.connect(self.threadFinished)
self.worker[i].finished.connect(self.workerFinished)
self.worker[i].intReady.connect(self.workerResultReady)
self.worker[i].finished.connect(self.threadx[i].quit)
self.threadx[i].started.connect(self.worker[i].procCounter)
self.destroyed.connect(self.threadx[i].deleteLater)
self.destroyed.connect(self.worker[i].deleteLater)
self.worker[i].moveToThread(self.threadx[i])
def startThread(self,i):
self.threadx[i].start()
@pyqtSlot(int)
def threadStarted(self,i):
print('Thread {} started'.format(i))
print("Thread priority is {}".format(self.threadx[i].priority()))
@pyqtSlot(int)
def threadFinished(self,i):
print('Thread {} finished'.format(i))
@pyqtSlot(int)
def threadTerminated(self,i):
print("Thread {} terminated".format(i))
@pyqtSlot(int,int)
def workerResultReady(self,j,i):
print('Worker {} result returned'.format(i))
if i ==0:
self.label1.setText("{}".format(j))
if i ==1:
self.label2.setText("{}".format(j))
if i ==2:
self.label3.setText("{}".format(j))
if i ==3:
self.label4.setText("{}".format(j))
@pyqtSlot(int)
def workerFinished(self,i):
print('Worker {} finished'.format(i))
def initUI(self):
self.label1 = QLabel("0")
self.label2= QLabel("0")
self.label3= QLabel("0")
self.label4 = QLabel("0")
grid = QGridLayout(self)
self.setLayout(grid)
grid.addWidget(self.label1,0,0)
grid.addWidget(self.label2,0,1)
grid.addWidget(self.label3,0,2)
grid.addWidget(self.label4,0,3)
self.move(300, 150)
self.setGeometry(0,0,300,300)
self.setWindowTitle('thread test')
self.show()
def closeEvent(self, event):
print('Closing')
i=0
while i <self.idealthreadcount:
self.threadx[i].quit()
i+=1
i=0
while i <self.idealthreadcount:
self.threadx[i].wait()
i+=1
event.accept()
if __name__=='__main__':
app = QApplication(sys.argv)
form = Form()
sys.exit(app.exec_())
Und der Arbeitercode unten
import sys
import unittest
from PyQt4.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
import time
import random
class Worker(QObject):
finished = pyqtSignal(int)
intReady = pyqtSignal(int,int)
def __init__(self, i=0):
'''__init__ is called while the worker is still in the Gui thread. Do not put slow or CPU intensive code in the __init__ method'''
super().__init__()
self.idd = i
@pyqtSlot()
def procCounter(self):
for j in range(1, 10):
random_time = random.weibullvariate(1,2)
time.sleep(random_time)
self.intReady.emit(j,self.idd)
print('Worker {0} in thread {1}'.format(self.idd, self.thread().idd))
self.finished.emit(self.idd)
if __name__=='__main__':
unittest.main()
self.finished
Signal erzeugt haben? Wenn ich beispielsweise nicht nur die Anzahl drucken möchte, möchte ich den Wert der Anzahl in einer QSpinBox anzeigen, die Teil meiner Benutzeroberfläche der anderen Klasse ist.