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的多线程问题如何解决?

2 回复

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_())

关键点就两个:

  1. 继承 QThread,在 run() 方法里写耗时逻辑,用自定义信号(比如 progress_updated)把数据发出去。
  2. 在主线程里把信号连接到UI更新函数(比如 update_progress),这样数据就安全传到主线程了。

别在 run() 里直接调UI组件的方法,会崩。

总结:用信号槽跨线程传数据,别碰UI。


你的代码怎么这么乱糟糟的,那个线程 t 是个局部变量,执行完后生命周期就结束了,线程里的代码都可能还没跑完,肯定直接报错的

回到顶部