pyqt5学习之QThread

摘要:
pyqt线程的使用非常简单——创建一个自定义类,使其从QThread继承,并实现其run()方法;您可以在使用线程时直接获取线程实例,并调用其start()函数来启动线程。业务的线程任务写在run()函数中。当run()退出时,线程几乎完成。

       pyqt的线程的使用非常简单-建立一个自定义的类(如thread),使它继承自QThread,并实现其run()方法即可; 在使用线程时可以直接得到thread实例,调用其start()函数即可启动线程。线程启动后,会自动调用其实现run方法,该方法就是线程的执行函数。

       业务的线程任务就写在run()函数中,当run()退出之后线程基本就结束了。

常用方法:strat():启动线程

          wait():阻值线程

          sleep():强制当前线程睡眠毫秒

常用信号:started:在开始执行run()函数前,从相关线程发射此信号

     finished:当程序完成业务逻辑时,从相关线程发射此信号

步骤:1.建立一个线程实例

      2.在主线程类创建一个属性连接子线程

      3.使用strat()开始子线程

pyqt5学习之QThread第1张pyqt5学习之QThread第2张
from PyQt5.QtCore import *
from PyQt5.Qt import *
from PyQt5.QtGui import *
import sys
import cgitb
sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')
class mythread(QThread):  # 步骤1.创建一个线程实例
    mysignal = pyqtSignal(tuple)  # 创建一个自定义信号,元组参数

    def __init__(self):
        super(mythread, self).__init__()


    def run(self):
        a = (1, 2)
        self.mysignal.emit(a)  # 发射自定义信号

class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.setWindowTitle('信号传输')
        self.resize(500,500)
        self.move(50,50)
        self.setup_ui()

        self.my_thread = mythread()  # 步骤2. 主线程连接子线
        self.my_thread.mysignal.connect(self.zhi)  # 自定义信号连接
        self.my_thread.start()   #  步骤3 子线程开始执行run函数

    def setup_ui(self):
        self.line1 = QLineEdit(self)
        self.line1.move(0,0)
        self.line1.resize(50,50)

        self.line2 = QLineEdit(self)
        self.line2.move(50, 50)
        self.line2.resize(50, 50)


    def zhi(self, zhi):
        a, b = zhi
        self.line1.setText(str(a))
        self.line2.setText(str(b))
if __name__ == '__main__':

    app = QApplication(sys.argv)

    window = Window()
    window.show()
    sys.exit(app.exec_())
QThread
 UI主线程传递数据给子线程:
pyqt5学习之QThread第3张pyqt5学习之QThread第4张
from PyQt5.QtCore import *
from PyQt5.Qt import *
from PyQt5.QtGui import *
import sys
import cgitb
sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')
class mythread(QThread):  # 步骤1.创建一个线程实例
    mysignal = pyqtSignal(tuple)  # 创建一个自定义信号,元组参数

    def __init__(self, a):  #通过初始化赋值的方式实现UI主线程传递值给子线程
        super(mythread, self).__init__()
        self.a = a

    def run(self):
        a = (1, 2)
        self.mysignal.emit(a)  # 发射自定义信号

class Window(QWidget):
    mysignal2 = pyqtSignal(tuple)
    def __init__(self):
        super(Window, self).__init__()
        self.setWindowTitle('信号传输')
        self.resize(500,500)
        self.move(50,50)
        self.setup_ui()



    def setup_ui(self):
        self.line1 = QLineEdit(self)
        self.line1.move(0,0)
        self.line1.resize(50,50)

        self.line2 = QLineEdit(self)
        self.line2.move(50, 50)
        self.line2.resize(50, 50)

        self.btn = QPushButton('按钮',self)
        self.btn.resize(50,50)
        self.btn.move(150,0)
        self.btn.clicked.connect(self.cao1)



    def zhi(self, zhi):
        a, b = zhi
        self.line1.setText(str(a))
        self.line2.setText(str(b))

    def cao1(self):
        self.my_thread = mythread(1)  # 步骤2. 主线程连接子线,同时传递一个值给子线程
        self.my_thread.mysignal.connect(self.zhi)  # 自定义信号连接
        self.my_thread.start()  # 步骤3 子线程开始执行run函数



if __name__ == '__main__':

    app = QApplication(sys.argv)

    window = Window()
    window.show()
    sys.exit(app.exec_())
View Code

 moveToThread:在主线程中将程序送到子线程中运行

pyqt5学习之QThread第5张pyqt5学习之QThread第6张
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import time
import cgitb
sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')

# 需要工作在子线程的程序继承的类必须是QObject
class Work(QObject):
    count = int(0)
    count_signal = pyqtSignal(int)

    def __init__(self, parent=None):
        super(Work, self).__init__(parent)
        self.run = True

    def work(self):
        print('current id', int(QThread.currentThreadId()))
        self.run = True
        while self.run:
            # print(str(self.count))
            self.count += 1
            self.count_signal.emit(self.count)
            time.sleep(1)

    def work_stop(self):
        self.run = False

class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.setup_ui()

        print('main id', int(QThread.currentThreadId()))

        self.thread = QThread()  # 这里设定的一个多线程是一个管理者
        self.worker = Work()  # 不能有父类
        self.worker.count_signal.connect(self.flush)

        self.worker.moveToThread(self.thread)  # 将耗时的类在设定的子线程中运行
        self.thread.finished.connect(self.finished)

    def setup_ui(self):
        self.setWindowTitle('movetothread')
        self.resize(500,500)

        self.btn1 = QPushButton('开始', self)
        self.btn1.resize(50,50)
        self.btn1.clicked.connect(self.workStart)

        self.btn2 = QPushButton('结束',self)
        self.btn2.resize(50, 50)
        self.btn2.move(0, 50)
        self.btn2.clicked.connect(self.workStop)

        self.label = QLabel(self)
        self.label.resize(100,100)
        self.label.move(100, 100)

    def flush(self, count):
        self.label.setText(str(count))

    def workStart(self):
        print('开始')
        self.btn1.setEnabled(False)
        self.thread.start()
        self.thread.started.connect(self.worker.work)  # 当子线程启动时,调用需要运行类的方法

    def workStop(self):
        print('结束')
        self.worker.work_stop()
        self.thread.quit()

    def finished(self):
        print('finish')
        self.btn1.setEnabled(True)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())
View Code

线程休眠唤醒

pyqt5学习之QThread第7张pyqt5学习之QThread第8张
from PyQt5.QtCore import QThread, QWaitCondition, QMutex, pyqtSignal
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QProgressBar

class Thread(QThread):
    valuechange = pyqtSignal(int)

    def __init__(self, *args, **kwargs):
        super(Thread, self).__init__(*args, **kwargs)
        self._isPause = False
        self._value = 0
        self.cond = QWaitCondition()
        # QWaitCondition用于多线程的同步,一个线程调用QWaitCondition.wait()阻塞等待,直到另一个线程调用QWaitCondition.wake()唤醒才继续往下执行.
        self.mutex = QMutex()  # 互斥锁

    def pause(self):
        self._isPause = True

    def resume(self):
        self._isPause = False
        self.cond.wakeAll()  # 唤醒所有线程

    def run(self):
        while 1:
            self.mutex.lock() # 加锁只能一个线程使用
            if self._isPause:
                self.cond.wait(self.mutex)
                # QWaitCondition.wait()在使用时必须传入一个上锁的QMutex对象
                # 在wait()执行过程中,mutex一直保持上锁状态,直到调用操作系统的wait_block在阻塞的一瞬间把mutex解锁(严格说
                # 来应该是原子操作,即系统能保证在真正执行阻塞等待指令时才解锁).另一线程唤醒后,wait()函数将在第一时间重新给
                # mutex上锁,直到显示调用mutex.unlock()解锁.
                # 由此可见,通过mutex把有严格时序要求的代码保护起来,同时把wakeAll()也用同一个mutex保护起来,这样能保证:
                # 一定先有wait(),再有wakeAll(),不管什么情况,都能保证这先后关系,而不至于摆乌龙.
            if self._value >100:
                self._value = 0
            self._value += 1
            self.valuechange.emit(self._value)
            self.msleep(100)
            self.mutex.unlock() # 解锁给接下来的线程使用

class Window(QWidget):
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        layout = QVBoxLayout(self)
        self.progressBar = QProgressBar(self)
        layout.addWidget(self.progressBar)
        layout.addWidget(QPushButton('休眠', self, clicked=self.doWait))
        layout.addWidget(QPushButton('唤醒', self, clicked=self.doWake))

        self.t = Thread(self)
        self.t.valuechange.connect(self.progressBar.setValue)
        self.t.start()

    def doWait(self):
        self.t.pause()

    def doWake(self):
        self.t.resume()

if __name__ == '__main__':
    import sys
    import cgitb
    sys.excepthook = cgitb.enable(1, None, 5, '')
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())
View Code

 线程挂起和唤醒

pyqt5学习之QThread第9张pyqt5学习之QThread第10张
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ctypes

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
import win32con
from win32process import SuspendThread, ResumeThread

class Worker(QThread):

    valueChanged = pyqtSignal(int)  # 值变化信号
    handle = -1

    def run(self):
        try:
            self.handle = ctypes.windll.kernel32.OpenThread(
                win32con.PROCESS_ALL_ACCESS, False, int(QThread.currentThreadId()))
            # 利用该方法得到线程的句柄,然后就可以通过SuspendThread和ResumeThread两个函数对其进行挂起与恢复
        except Exception as e:
            print('get thread handle failed', e)
        print('thread id', int(QThread.currentThreadId()))
        for i in range(1, 101):
            print('value', i)
            self.valueChanged.emit(i)
            QThread.sleep(1)


class Window(QWidget):

    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        layout = QVBoxLayout(self)
        self.progressBar = QProgressBar(self)
        self.progressBar.setRange(0, 100)
        layout.addWidget(self.progressBar)

        self.startButton = QPushButton('开启线程', self, clicked=self.onStart)
        layout.addWidget(self.startButton)

        self.suspendButton = QPushButton(
            '挂起线程', self, clicked=self.onSuspendThread, enabled=False)
        layout.addWidget(self.suspendButton)

        self.resumeButton = QPushButton(
            '恢复线程', self, clicked=self.onResumeThread, enabled=False)
        layout.addWidget(self.resumeButton)

        self.stopButton = QPushButton(
            '终止线程', self, clicked=self.onStopThread, enabled=False)
        layout.addWidget(self.stopButton)

        # 当前线程id
        print('main id', int(QThread.currentThreadId()))

        # 子线程
        self._thread = Worker(self)
        self._thread.finished.connect(self._thread.deleteLater)
        self._thread.valueChanged.connect(self.progressBar.setValue)

    def onStart(self):
        print('main id', int(QThread.currentThreadId()))
        self._thread.start()  # 启动线程
        self.startButton.setEnabled(False)
        self.suspendButton.setEnabled(True)
        self.stopButton.setEnabled(True)

    def onSuspendThread(self):
        if self._thread.handle == -1:
            return print('handle is wrong')
        ret = SuspendThread(self._thread.handle)
        print('挂起线程', self._thread.handle, ret)
        self.suspendButton.setEnabled(False)
        self.resumeButton.setEnabled(True)

    def onResumeThread(self):
        if self._thread.handle == -1:
            return print('handle is wrong')
        ret = ResumeThread(self._thread.handle)
        print('恢复线程', self._thread.handle, ret)
        self.suspendButton.setEnabled(True)
        self.resumeButton.setEnabled(False)

    def onStopThread(self):
        self.startButton.setEnabled(False)
        self.suspendButton.setEnabled(False)
        self.resumeButton.setEnabled(False)
        ret = ctypes.windll.kernel32.TerminateThread(
            self._thread.handle, 0)
        # 终止线程,不推荐
        print('终止线程', self._thread.handle, ret)
        self.stopButton.setEnabled(False)

    def closeEvent(self, event):
        if self._thread.isRunning():
            self._thread.quit()
            # 强制
            # self._thread.terminate()
        del self._thread
        super(Window, self).closeEvent(event)


if __name__ == '__main__':
    import sys
    import os
    print('pid', os.getpid())
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())
View Code

线程的休眠唤醒用的是python线程的方法;线程的挂起和唤醒用的是C++线程方法

免责声明:文章转载自《pyqt5学习之QThread》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇windows 和office破解C#中json字符串的序列化和反序列化下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

2019年北航OO第二单元(多线程电梯任务)总结

一、三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程。这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以将调度器上纷繁的逻辑判断分布在不同的人身上,大大简化了代码逻辑。对于程序复杂度,将人作为某个容器中的PersonRequest时需要在电梯到达某一层时进行遍历...

死锁检测

曾经参与过的一款网络游戏,其服务器使用了异常复杂的多线程序解决方案。导致应用层程序员编写的代码很容易就出现死锁。 最终,公司的一个老员工,只能开发了一个死锁检测框架,在debug模式下运行时,只要发生死锁就会打印出调用堆栈。 虽然说这个框架基本可以在上线前把所有的死锁都检测了出来,但是,规根到底这是设计不合理造成的,多线程利用好了会提升 应用的效率,用不好...

iOS开发-Runloop详解(简书)

不知道大家有没有想过这个问题,一个应用开始运行以后放在那里,如果不对它进行任何操作,这个应用就像静止了一样,不会自发的有任何动作发生,但是如果我们点击界面上的一个按钮,这个时候就会有对应的按钮响应事件发生。给我们的感觉就像应用一直处于随时待命的状态,在没人操作的时候它一直在休息,在让它干活的时候,它就能立刻响应。其实,这就是run loop的功劳。 一、线...

Linux-c 线程锁

1 typedef struct_my_mutex { 2 pthread_mutex_t mutex; //互斥锁 3 pthread_mutexattr_t mta; //互斥锁属性 4 } my_mutex; 转自:http://blog.sina.com.cn/s/blog_8795b0970101il6g.html 在Posix Threa...

响应式编程系列(一):什么是响应式编程?reactor入门

响应式编程 系列文章目录 (一)什么是响应式编程?reactor入门 (二)Flux入门学习:流的概念,特性和基本操作 (三)Flux深入学习:流的高级特性和进阶用法 (四)reactor-core响应式api如何测试和调试? (五)Spring reactive: Spring WebFlux的使用 (六)Spring reactive: webClie...

java.lang.OutOfMemoryError: unable to create new native thread问题排查以及当前系统最大进程数量

1. 问题描述 线上某应用出问题,查看日志 这一组服务器是2台,每台都有。配置为64G,使用7G,空余内存非常多 2. 问题排查 环境变化:程序迁移到新机器,新机器是CentOS 7,程序运行账号由原来的root改为work。硬件配置由32G升级为64G。首先切换到work账号,然后运行一个测试程序就是建立线程,发现只能跑2900多个,我的笔记本还能跑2...