QThread管理任务

2024-03-29 05:43:35 发布

您现在位置:Python中文网/ 问答频道 /正文

当我最多只有4个线程时,qthread如何管理正在处理的线程数? 例如,假设我有100个长处理任务。当我遍历100个树视图项并发出一个Qthread来处理每个任务时,会发生什么?它是否自动确定我只有4个线程,并在4个可用线程中处理100个线程

好奇。 谢谢

import os
import sys
import time
import random
from PySide2 import QtCore, QtGui, QtWidgets


class TaskThread(QtCore.QThread):
    
    finished = QtCore.Signal(object)

    def __init__(self, index):
        super(TaskThread, self).__init__()        
        self._index = index

    def runTask(self, task):
        self._task = task

    def run(self):
        t = random.randint(0,4)
        time.sleep(t)
        self.finished.emit(self._index)


class ExampleDialog(QtWidgets.QDialog):

    def __init__(self):
        super(ExampleDialog, self).__init__()
        
        self.itemModel = QtGui.QStandardItemModel()

        self.uiListView = QtWidgets.QListView()
        self.uiListView.setModel(self.itemModel)

        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.addWidget(self.uiListView)

        self.populateItems()


    def populateItems(self):
        self.threads = []
        for x in range(100):
            output = 'C:/Users/JokerMartini-Asus/Desktop/Trash/thumbs/IMG_409{}.jpg'.format(x)

            # Item
            item = QtGui.QStandardItem('{}'.format(x))
            item.setData(QtGui.QPixmap(), QtCore.Qt.DecorationRole)
            item.setData(output, QtCore.Qt.UserRole)
            self.itemModel.appendRow(item)

            mIndex = QtCore.QPersistentModelIndex(self.itemModel.indexFromItem(item))
            tt = TaskThread(mIndex)
            
            self.threads.append(tt)
            tt.start()
            tt.finished.connect(self.processFinished)


    def processFinished(self, index):
        if index.isValid():
            model = index.model()
            model.setData(index, '{} updated'.format(index.row()), QtCore.Qt.DisplayRole)


if __name__ == '__main__':
    pass
    app = QtWidgets.QApplication(sys.argv)
    window = ExampleDialog()
    window.resize(300,600)
    window.show()
    window.raise_()
    sys.exit(app.exec_())

Tags: importselfindexinitdefsyswindowitem
1条回答
网友
1楼 · 发布于 2024-03-29 05:43:35

注意:我的回答仅基于经验实验和线程的基本知识。对于线程的底层实现,我没有足够的知识来提供我所表达的内容的可靠资源,也不能证明这在所有支持Qt的平台上都是有效的(我在Linux上)。

<> P>在处理线程时有两件重要的事情要考虑,即使Qt绑定:

  1. 线程不是“加速”事情,而是允许在其他人暂时空闲时处理计算
  2. GIL一次只允许对每个进程执行一个操作,我们感觉到明显的“并行性”是因为每个线程临时将控制权释放给另一个线程

从根本上说,没有绝对顺序,在python中,线程没有严格的优先级(由于上述原因):从理论上讲,处理是[几乎]按照线程启动的顺序进行的,但结果可能会因每个线程处理的“速度”而有所不同,即使对于相同的操作也是如此。一旦一个线程将控制权释放给GIL,“下一个”线程就会得到它

通过对代码添加以下更改,您可以看到更可靠的结果:

class TaskThread(QtCore.QThread):
    # ...
    def run(self):
        # always use the same timeout
        time.sleep(1)
        self.finished.emit(self._index)


class ExampleDialog(QtWidgets.QDialog):
    # ...
    def processFinished(self, index):
        while app.hasPendingEvents():
            app.processEvents()
            time.sleep(.05)
        self.uiListView.repaint()
        # ...

注意:上面的代码将阻塞UI,hasPendingEvents被认为是过时的,因为线程的并发性,出于同样的原因,不鼓励使用processEvents;只考虑教育目的。

这意味着三件事:

  • 一般来说,python中对并发线程没有“限制”(因为线程不是并发的)
  • 在python中,重载计算实际上不是与线程并行的
  • 最重要的是,当谈到线程时,“核心”的数量是完全没有意义的(特别是在python中):在相同的情况下,2核CPU的结果与8核CPU相同

真正的并行性只能通过多进程实现,但问题是进程与线程不同,不共享内存。这并不意味着这是完全不可能的:thislink声称他们实现了对Qt信号/插槽机制的适当的多处理支持,但我从未尝试过,也不能说它真的有效(特别是考虑到该链接已经很旧)

注意:您不应该在线程启动后连接它的信号,特别是如果该线程可能立即返回(time.sleep(0));将tt.finished.connect移动到tt.start()之前。

相关问题 更多 >