如何在线程qthreadpool之后执行代码?

How to execute code after threads qthreadpool?

我有一个实现了 3 个按钮的 GUI 其中一个按钮绑定了“开始”功能,其中包含 2 个进程,事实上,这两个循环应该可以多线程工作,但我需要向“开始”功能添加更多代码,例如,更改一些小部件. 问题是,如果我在 self.threadpool.start(thread2) self.threadpool.start(thread3) 之后添加一些代码,那么它不会在这些线程完成时执行,而是在此之前执行,或者根本不执行。

我写了一个玩具示例,完全描述了我对程序的要求

import sys
import time
from PySide2.QtCore import QThreadPool, QRunnable, Slot
from PySide2.QtWidgets import QApplication, QWidget, QPushButton

class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.threadpool = QThreadPool()
        self.btn.clicked.connect(lambda: self.start())

    def start(self):
        t1 = Worker(th1)
        t2 = Worker(th2)
        self.btn.setEnabled(False)
        self.threadpool.start(t1)
        self.threadpool.start(t2)
        self.btn.setEnabled(True)

    def initUI(self):
        self.btn = QPushButton('Start', self)
        self.btn.resize(self.btn.sizeHint())
        self.btn.move(50, 50)
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('HELP')
        self.show()


class Worker(QRunnable):

    def __init__(self, fn):
        super(Worker, self).__init__()
        self.fn = fn

    @Slot()  # QtCore.Slot
    def run(self):
        self.fn()


def th1():
    time.sleep(5)
    print("th1")


def th2():
    time.sleep(10)
    print("th2")


app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

我需要按钮在流开始前关闭并在流完成后才打开。

该解决方案对于我想在流之后使用的任何代码都应该是公平的。

首先,在 QRunnable 的方法中使用 Slot 装饰器是没有用的,因为它不是 QObject。

另一方面,实现多线程逻辑的想法是主线程不阻塞,所以你不应该期望在调用start()后它会在执行完线程后执行。

解决方案是创建一个在线程执行前后发出信号的 QObject,并使用该逻辑实现 GUI 更新:

import sys
import time

from PySide2.QtCore import QObject, QThreadPool, QRunnable, Signal, Slot
from PySide2.QtWidgets import QApplication, QWidget, QPushButton


class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.active_workers = 0
        self.threadpool = QThreadPool()
        self.btn.clicked.connect(self.start)

    @Slot()
    def start(self):
        t1 = Worker(th1)
        t1.signaller.started.connect(self.on_started)
        t1.signaller.finished.connect(self.on_finished)

        t2 = Worker(th2)
        t2.signaller.started.connect(self.on_started)
        t2.signaller.finished.connect(self.on_finished)

        self.btn.setEnabled(False)

        self.threadpool.start(t1)
        self.threadpool.start(t2)

    def initUI(self):
        self.btn = QPushButton("Start", self)
        self.btn.resize(self.btn.sizeHint())
        self.btn.move(50, 50)
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle("HELP")
        self.show()

    @Slot()
    def on_started(self):
        self.active_workers += 1

    @Slot()
    def on_finished(self):
        self.active_workers -= 1
        self.btn.setEnabled(self.active_workers == 0)


class Signaller(QObject):
    started = Signal()
    finished = Signal()


class Worker(QRunnable):
    def __init__(self, fn):
        super(Worker, self).__init__()
        self.signaller = Signaller()
        self.fn = fn

    def run(self):
        self.signaller.started.emit()
        self.fn()
        self.signaller.finished.emit()


def th1():
    time.sleep(5)
    print("th1")


def th2():
    time.sleep(10)
    print("th2")


app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())