为什么延迟会改变正在运行的QThreads的数量?

时间:2017-09-30 10:37:25

标签: python multithreading pyqt pyqt5 sleep

以下示例程序使用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调用会改变正在运行的线程数?

1 个答案:

答案 0 :(得分:1)

前三个工作对象容易进行垃圾收集,而第四个工作对象则作为全局变量。 sleep允许每个线程有足够的时间来调用其关联工作者的work方法,这将使它们全部保持活动状态(因为这些方法会阻塞while循环)。如果没有sleep,前三个工作人员将立即被垃圾收集,只留下第四个来处理队列。如果工作者被保存在列表中(与线程相同),您应该看到所有被利用(有或没有睡眠)。

要证明这是正在发生的事情,您可以将其添加到Worker类:

class Worker(QObject)
    ...

    def __del__(self):
        print('deleted:', self.number)