如何在线程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_())
我有一个实现了 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_())