Python中关于PyQt5的多线程问题如何解决?
代码如下
# coding: utf-8
import sys
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QApplication
class Worker(QThread):
finish_signal = pyqtSignal(str)
def init(self):
super(Worker, self).init()
self.id = 0
self.li = []
def receive_ele(self, ele):
id, other = [int(i) for i in ele.split('_')]
if id != self.id:
return
self.li.append(other)
def run(self):
while 1:
if not self.li:
continue
li, self.li = self.li, []
ele = 0
for ele in li:
pass
self.finish_signal.emit("{}_{}".format(self.id, ele))
# QThread.sleep(1)
class Example(QWidget):
id_signal = pyqtSignal(str)
def init(self, parent=None):
super(Example, self).init(parent=parent)
# self.initUI()
self.data = [ i for i in range(1000)]
self.signals = [0]
self.initUI()
def initUI(self):
# Worker.finish_signal.connect(self.receive_finish)
for i in range(10):
t = Worker()
t.id = i+1
t.finish_signal.connect(self.receive_finish)
# self.signals.append(pyqtSignal(str))
self.id_signal.connect(t.receive_ele)
t.start()
ele = self.data.pop(0)
self.id_signal.emit("{}_{}".format(t.id, ele))
self.setGeometry(300, 300, 500, 500)
self.setWindowTitle("signal test")
print("show")
self.show()
def receive_finish(self, str):
id, num = str.split('_')
id, num = int(id), int(num)
if self.data:
ele = self.data.pop(0)
else:
ele = 0
print("thread:{}, finish num:{}, prepare:{}".format(id, num, ele))
if ele != 0:
self.id_signal.emit("{}_{}".format(id, ele))
if name == ‘main’:
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
开 10 个子线程,脚本启动不了,只能开一个子线程,这是为什么呀,我想要开 10 个或者 100 个子线城应该怎么办?
Python中关于PyQt5的多线程问题如何解决?
PyQt5的多线程问题核心在于不能在工作线程里直接操作UI组件,得用信号槽机制。
比如你要在后台跑个耗时任务,同时更新进度条,可以这么搞:
import sys
import time
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QProgressBar
from PyQt5.QtCore import QThread, pyqtSignal
class WorkerThread(QThread):
# 定义信号,用来传数据给主线程
progress_updated = pyqtSignal(int)
task_finished = pyqtSignal()
def run(self):
for i in range(1, 101):
time.sleep(0.05) # 模拟耗时操作
self.progress_updated.emit(i) # 发射进度信号
self.task_finished.emit() # 发射完成信号
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
self.worker = WorkerThread()
self.worker.progress_updated.connect(self.update_progress)
self.worker.task_finished.connect(self.on_task_finished)
def init_ui(self):
self.setWindowTitle('PyQt5多线程示例')
layout = QVBoxLayout()
self.progress_bar = QProgressBar()
self.btn_start = QPushButton('开始任务')
self.btn_start.clicked.connect(self.start_task)
layout.addWidget(self.progress_bar)
layout.addWidget(self.btn_start)
self.setLayout(layout)
def start_task(self):
self.btn_start.setEnabled(False)
self.worker.start()
def update_progress(self, value):
self.progress_bar.setValue(value) # 主线程安全更新UI
def on_task_finished(self):
self.btn_start.setEnabled(True)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
关键点就两个:
- 继承
QThread,在run()方法里写耗时逻辑,用自定义信号(比如progress_updated)把数据发出去。 - 在主线程里把信号连接到UI更新函数(比如
update_progress),这样数据就安全传到主线程了。
别在 run() 里直接调UI组件的方法,会崩。
总结:用信号槽跨线程传数据,别碰UI。
你的代码怎么这么乱糟糟的,那个线程 t 是个局部变量,执行完后生命周期就结束了,线程里的代码都可能还没跑完,肯定直接报错的

