На основі методів об’єктів Worker, згаданих в інших відповідях, я вирішив подивитися, чи можу я розширити рішення, щоб викликати більше потоків - в цьому випадку оптимальне число, яке може запустити машина, і закрутити декількох працівників з невизначеним часом завершення. Для цього мені все одно потрібно підклас QThread - але лише для присвоєння номера потоку та для «перевстановлення» сигналів «закінчений» та «запущений» для включення номера потоку.
Я досить зосередився на сигналах між головним графічним інтерфейсом, потоками та працівниками.
Подібним чином, інші відповіді були великим зусиллям, щоб вказати на те, що не є вихователем QThread, але я не думаю, що це справді хвилює. Однак мій код також обережно знищує об'єкти QThread.
Однак я не зміг виховувати робочі об'єкти, тому бажано надіслати їм сигнал deleteLater (), або коли функція потоку закінчена, або графічний інтерфейс знищений. У мене був свій власний код, який не робив цього.
Ще одним удосконаленням, яке, на мою думку, було необхідним, було перевтілення closeEvent графічного інтерфейсу (QWidget) таким чином, щоб потокам було наказано вийти, а потім графічний інтерфейс зачекав, поки всі потоки не закінчаться. Коли я грав з деякими іншими відповідями на це питання, я отримав QThread знищені помилки.
Можливо, це буде корисно іншим. Я, звичайно, знайшов це корисною вправою. Можливо, інші знатимуть кращий спосіб для нитки оголосити свою ідентичність.
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_())
І робочий код нижче
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
сигнал? Наприклад, якщо замість того, щоб просто надрукувати рахунок, я хочу відобразити значення count у QSpinBox, яке є частиною мого графічного інтерфейсу з іншого класу.