以下示例程序使用QThread
实例从队列中运行作业。
from queue import Queue
from sys import argv
from threading import Lock
from time import sleep
from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication
class Worker(QObject):
finished = pyqtSignal()
def __init__(self, number):
super().__init__()
self.number = number
@pyqtSlot()
def work(self):
while True:
job = queue.get()
if job is None:
self.finished.emit()
return
with lock:
print('worker={} job={}'.format(self.number, job))
sleep(1)
app = QApplication(argv)
lock = Lock()
queue = Queue()
threads = []
nthreads = 4
for ithread in range(nthreads):
thread = QThread()
worker = Worker(ithread + 1)
worker.moveToThread(thread)
thread.started.connect(worker.work)
worker.finished.connect(thread.quit)
thread.start()
threads += [thread]
#-----------
sleep(1e-10)
#-----------
for ijob in range(10):
queue.put(ijob + 1)
for _ in range(nthreads):
queue.put(None)
for thread in threads:
thread.wait()
通过sleep
调用(参见标记行),所有线程都按预期运行。输出:
worker=1 job=1
worker=2 job=2
worker=3 job=3
worker=4 job=4
[…]
没有调用,就会运行任意数量的线程。输出:
worker=4 job=1
worker=4 job=2
worker=4 job=3
worker=4 job=4
[…]
我已经使用Python 3.6.2中的PyQt 5,其他版本,可变睡眠持续时间,不同语句顺序和运行事件循环对此进行了测试。
为什么sleep
调用会改变正在运行的线程数?
答案 0 :(得分:1)
前三个工作对象容易进行垃圾收集,而第四个工作对象则作为全局变量。 sleep
允许每个线程有足够的时间来调用其关联工作者的work
方法,这将使它们全部保持活动状态(因为这些方法会阻塞while循环)。如果没有sleep
,前三个工作人员将立即被垃圾收集,只留下第四个来处理队列。如果工作者被保存在列表中(与线程相同),您应该看到所有被利用(有或没有睡眠)。
要证明这是正在发生的事情,您可以将其添加到Worker
类:
class Worker(QObject)
...
def __del__(self):
print('deleted:', self.number)