作者 | 万里羊责编 | 王晓曼出品 | CSDN博客线程和进程计算机的核心是CPU,它承担了所有的计算任务,就像是一座工厂在时刻运行。如果工厂的资源有限,一次只能供一个车间来使用,也就是说当一个车间开工时其它车间不能工作,也就是一个CPU一次只能执行一个任务。进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。当然一个车间还有很多工人,他们互相协同完成一个工作;而线程就好比工厂的工人,一个进程可以包含多个线程。线程(Thread)也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。多线程与多进程通俗易懂的理解就是:

多进程:允许多个任务同时进行多线程:允许单个任务分成不同的部分运行

Python多线程的实现Python3 通过两个标准库 thread(python2中是thread模块)和 threading 提供对线程的支持。thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。threading:

import threading #导入threading库import timedef run(n):    print("task", n)    time.sleep(1) #延时一秒    print('2s')    time.sleep(1)    print('1s')    time.sleep(1)    print('0s')    time.sleep(1)if __name__ == '__main__':    t1 = threading.Thread(target=run, args=("t1",))#创建线程1,取名为t1    t2 = threading.Thread(target=run, args=("t2",))#创建线程2,取名为t2    t1.start() #开启线程t1    t2.start() #开启线程t2

输出结果:

task t1task t22s2s1s1s0s0s

可以看出先开启了线程t1,在开启t2然后每隔一秒打印数据。自定义线程通过继承threading.Thread来自定义线程类,其本质是重构Thread类中的run方法:

import threadingimport timeclass MyThread(threading.Thread):def __init__(self, n):        super(MyThread, self).__init__()  # 重构run函数必须要写        self.n = ndef run(self):        print("task", self.n)        time.sleep(1)        print('2s')        time.sleep(1)        print('1s')        time.sleep(1)        print('0s')        time.sleep(1)if __name__ == "__main__":    t1 = MyThread("t1")    t2 = MyThread("t2")    t1.start()    t2.start()

输出结果:

task t1task t22s2s1s1s0s0s

守护线程 下面这个例子,使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,因此当主进程结束后,子线程也会随之结束。所以当主线程结束后,整个程序就退出了。

import threadingimport timedef run(n):    print("task", n)    time.sleep(1)       #此时子线程停1s    print('3')    time.sleep(1)    print('2')    time.sleep(1)    print('1')if __name__ == '__main__':    t = threading.Thread(target=run, args=("t1",))    t.setDaemon(True)   #把子进程设置为守护线程,必须在start()之前设置    t.start()    print("end")

输出结果:

task t1end

可以看到,t1线程并没有执行完毕,而是直接结束了。说明设置子线程为守护线程之后,主线程结束了,子线程也立即结束不再执行。程序中不是只创建了一个线程么?怎么会有主线程和子线程呢?其实呢程序运行时就会创建一个线程,而这个线程就是主线程。主线程等待子线程运行结束

import threadingimport timedef run(n):    print("task", n)    time.sleep(1)          print('3')    time.sleep(1)    print('2')    time.sleep(1)    print('1')if __name__ == '__main__':    t = threading.Thread(target=run, args=("t1",))    t.setDaemon(True)   #把子进程设置为守护线程,必须在start()之前设置    t.start()    t.join() # 设置主线程等待子线程结束    print("end")

输出结果:

task t1321end

运行.join()后的程序表明等待所有线程结束以后再进行.join()之后的操作结合以上代码就是,等待t1结束以后再执行end。多线程共享全局变量线程是进程的执行单元,进程是系统分配资源的最小单位,所以在同一个进程中的多线程是共享资源的。那么共享资源时就需要用到全局变量。

import threadingimport timenum = 100def work1():global numfor i in range(3):        num += 1    print("in work1 num is : %d" % num)def work2():global num    print("in work2 num is : %d" % num)if __name__ == '__main__':    t1 = threading.Thread(target=work1)    t1.start()    time.sleep(1)    t2 = threading.Thread(target=work2)    t2.start()

运行结果如下:

in work1 num is : 103in work2 num is : 103

可以看到两者输出的结果是相同的,说明是可以共享全局变量的。互斥锁由于线程之间是进行随机调度,并且每个线程可能只执行n条,当多个线程同时修改同一条数据时可能会出现脏数据,因而,出现了线程锁,即同一时刻只允许一个线程执行操作。线程锁用于锁定资源,可以定义多个锁, 在下面的实例中, 当你需要独占某一资源时,任何一个锁都可以锁这个资源,就好比你用不同的锁都可以把相同的一个门锁住是一个道理。由于线程之间是进行随机调度,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,我们也称此为“线程不安全”。为了方式上面情况的发生,就出现了互斥锁(Lock):

import threadingdef work1():global A,lock#定义A和lock为全局变量lock.acquire()#上锁for i in range(5):        A+=1        print('work1',A)lock.release()#解锁def work2():global A,locklock.acquire()for i in range(5):        A+=10        print('work2',A)lock.release()if __name__=='__main__':lock=threading.Lock()#定义锁    A=0    t1=threading.Thread(target=work1)    t2=threading.Thread(target=work2)    t1.start()    t2.start()    t1.join()    t2.join()

输出结果:

work1 1work1 2work1 3work1 4work1 5work2 15work2 25work2 35work2 45work2 55

可以发现对两组数据是没有影响的,感兴趣的可以尝试一下不加锁会有什么情况。递归锁RLcok类的用法和Lock类一模一样,但它支持嵌套,在多个锁没有释放的时候一般会使用RLcok类。

import threadingimport timedef Func(lock):global gl_numlock.acquire()    gl_num += 1    time.sleep(1)    print(gl_num)lock.release()if __name__ == '__main__':    gl_num = 0lock = threading.RLock()for i in range(10):        t = threading.Thread(target=Func, args=(lock,))        t.start()

输出结果:

12345678910

信号量(BoundedSemaphore类)互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。实际中博主还没有用到过,所以理解不是特别透彻。

import threadingimport timedef run(n, semaphore):    semaphore.acquire()   #加锁    time.sleep(1)    print("run the thread:%s\n" % n)    semaphore.release()     #释放if __name__ == '__main__':    num = 0    semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行for i in range(22):        t = threading.Thread(target=run, args=("t-%s" % i, semaphore))        t.start()while threading.active_count() != 1:pass  # print threading.active_count()else:        print('-----all threads done-----')

输出结果有点长,就不贴输出结果了。事件(Event类)python线程的事件用于主线程控制其他线程的执行,事件是一个简单的线程同步对象,其主要提供以下几个方法:

  • clear 将flag设置为“False”;
  • set 将flag设置为“True”;
  • is_set 判断是否设置了flag;
  • wait 会一直监听flag,如果没有检测到flag就一直处于阻塞状态。

事件处理的机制:全局定义了一个“Flag”,当flag值为“False”,那么event.wait()就会阻塞,当flag值为“True”,那么event.wait()便不再阻塞:

import threadingimport timeevent = threading.Event()def lighter():    count = 0    event.set()     #初始值为绿灯while True:if 5 10 :            event.clear()  # 红灯,清除标志位            print("1mred light is on...")elif count > 10:            event.set()  # 绿灯,设置标志位            count = 0else:            print("mgreen light is on...")        time.sleep(1)        count += 1def car(name):while True:if event.is_set():      #判断是否设置了标志位            print("[%s] running..."%name)            time.sleep(1)else:            print("[%s] sees red light,waiting..."%name)            event.wait()            print("[%s] green light is on,start going..."%name)light = threading.Thread(target=lighter,)light.start()car = threading.Thread(target=car,args=("MINI",))car.start()

这段代码模拟红绿灯,很形象。Qthread本以为我学完了多线程就完事了,就可以将语音和QT界面进行整合了。当我去实现的时候发现问题不是这么简单,通过语音控制打开一个特定的界面可以实现,但是为什么只要这个特定的界面关闭了,我语音的线程也就结束了。困惑了我好久,最后终于在某社区发现了答案!原来QT自带的有Qthread,当多线程涉及到界面交互时最好用Qthread来实现。然后又查阅大量博客,看了大量代码。在使用继承QThread的run方法之前需要了解一条规则:QThread只有run函数是在新线程里的,其他所有函数都在QThread生成的线程里

  • QThread只有run函数是在新线程里的;
  • QThread只有run函数是在新线程里的;
  • QThread只有run函数是在新线程里的。

那么我就在网上找到了这个计时器的例子:

#coding=utf-8import sysfrom PyQt5.QtGui import *from PyQt5.QtWidgets import *from PyQt5.QtCore import *count = 0# 工作线程class WorkThread(QThread):# pyqtSignal是信号类    timeout = pyqtSignal()  # 每隔一秒发送一个信号end = pyqtSignal()  # 计数完成后发送一个信号def run(self):while True:# 休眠1秒self.sleep(1)if count == 5:self.end.emit()  # 发送end信号,调用和end信号关联的方法breakself.timeout.emit()  # 发送timeout信号class Counter(QWidget):def __init__(self):super(Counter, self).__init__()self.setWindowTitle("用QThread编写计数器")self.resize(600, 400)        layout = QVBoxLayout()# QLCDNumber 用于模拟LED显示效果,类似于Labelself.lcdNumber = QLCDNumber()        layout.addWidget(self.lcdNumber)        button = QPushButton("开始计数")        layout.addWidget(button)self.workThread = WorkThread()self.workThread.timeout.connect(self.countTime)self.workThread.end.connect(self.end)        button.clicked.connect(self.work)self.setLayout(layout)def countTime(self):        global count        count += 1self.lcdNumber.display(count)def end(self):        QMessageBox.information(self, '消息', '计数结束', QMessageBox.Ok)        global count        count =0def work(self):self.workThread.start()if __name__ == "__main__":    app = QApplication(sys.argv)    main = Counter()    main.show()    sys.exit(app.exec_())

点击开始计时就会出现类似LCD的显示,计时到5秒结束后弹窗提醒。运行结果如下:通过这个例程让我对Qthread有了更好的理解,经管理解的不是特别透彻但是我知道怎么来改出来我想用的代码。之前提到的打开窗口线程阻塞,关闭窗口线程重启,其实这个计时器是一个很好的例子,但是关于线程阻塞.wait不好使。我的方法是定义一个全局变量mode=0(用来判断是否需要阻塞线程),如果窗口打开后那么给这个全局赋值mode=1,在run函数里对这个mode进行判断,如果mode等于1那么可以用一个循环来延时实现。

if mode:while(mode):self.sleep(1)

当窗口关闭以后给mode 赋值等于0通过这种方法可以实现,很多小伙伴又会问怎么判断窗口打开和关闭,其实在自己写的窗口函数最前面加mode=1和最后面mode=0就可以了不用进行判断。版权声明:本文为CSDN博主「万里羊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_44895651/article/details/105877358

更多精彩推荐

☞那些被大数据时代抛弃的人

☞反转!物联网火爆,开发者却太难了!

☞小米回应林斌退休传闻;哈工大等高校被禁止使用 MATLAB;统信软件 UOS20 SP1 系统升级| 极客头条

☞一篇与众不同的 String、StringBuilder 和 StringBuffer 详解

☞利用 AssemblyAI 在 PyTorch 中建立端到端的语音识别模型

☞赠书 | 供应链金融模式有哪些?区块链在供应链金融中如何应用?

你点的每个“在看”,我都认真当成了喜欢

c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划相关推荐

  1. Java多线程之----主线程会等待子线程结束再结束么,怎么让主线程等待子线程结束呐?

    首先给出结论: 主线程和子线程之间没有谁先谁后结束这种关联,它们只是各自负责自己的线程任务,如果该线程的任务结束了,该线程自然会结束运行. talk is cheap,show me the code ...

  2. 【多线程】学习记录七种主线程等待子线程结束之后在执行的方法

    最近遇到一个问题需要主线程等待所有的子线程结束,才能开始执行,统计所有的子线程执行结果,返回,网上翻阅各种资料,最后记录一下,找到七种方案 第一种:while循环 对于"等待所有的子线程结束 ...

  3. VC++ 中主线程等待子线程结束的方法

    void WaitForThreadExit(void) {DWORD dwRet; //返回值MSG msg; int wait_count=4; //线程句柄有4个int nExitThreadC ...

  4. Java多线程协作CountDownLatch,主线程等待子线程结束

    CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 主要方法 public CountDownLatch(int count);构造方 ...

  5. 如何实现java主线程等待子线程执行完毕之后再执行?

    本文转自:问题:如何实现java主线程等待子线程执行完毕之后再执行? - jseven - 博客园 点击关注强哥,查看更多精彩文章呀 工作总往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完 ...

  6. Java并发编程原理与实战六:主线程等待子线程解决方案

    Java并发编程原理与实战六:主线程等待子线程解决方案 参考文章: (1)Java并发编程原理与实战六:主线程等待子线程解决方案 (2)https://www.cnblogs.com/pony1223 ...

  7. java 主线程等待_Java实现主线程等待子线程

    本文介绍两种主线程等待子线程的实现方式,以5个子线程来说明: 1.使用Thread的join()方法,join()方法会阻塞主线程继续向下执行. 2.使用Java.util.concurrent中的C ...

  8. Java主线程等待子线程、线程池

    public class TestThread extends Thread { public void run() { System.out.println(this.getName() + &qu ...

  9. java等待5秒_Java并发编程-主线程等待子线程解决方案

    主线程等待所有子线程执行完成之后,再继续往下执行的解决方案 public class TestThread extends Thread { public void run() { System.ou ...

最新文章

  1. 蓝桥杯 兰顿蚂蚁(模拟)
  2. s5pv210运行裸机程序的方法之在SDRAM(DDR2)中运行
  3. TiDB 在威锐达 WindRDS 远程诊断及运维中心的应用
  4. SQL基础---SQL WHERE 子句
  5. Dll注入经典方法完整版
  6. 狄克斯特拉算法(入门)
  7. mysql 分段执行_面试官问你MySQL的优化,看这篇文章就够了
  8. Python模拟登陆 —— 征服验证码 7 京东
  9. 计算机系要考英语口语吗,2015年高考英语口语由计算机“打分”,这些细节要注意!...
  10. 类似鹅厂的H5农场游戏,牧场游戏 博主亲自搭建
  11. 大学本科基于html5毕业设计题目50例
  12. android词根词缀,词根词缀记忆字典 - 好担心你们因为它的界面丑,而错过这款背单词神器 - Android 应用 - 【最美应用】...
  13. obs多推流地址_推流篇| 如何在广交会直播中使用OBS推流,播放视频、PPT等
  14. 基于DAC8563模块的低速模拟振镜驱动,实现直线插补,点到点划线
  15. 迅雷手机版苹果版_IOS手机迅雷下载(支持苹果手机和ipad)
  16. React报错 Too many re-renders
  17. 哪里东西更便宜?读《卧底经济学(珍藏版)》
  18. (自学)sklearn决策树基础知识|解决centos7.8 graphviz报错不能画图的问题
  19. python归一化 增大差异_Python实现描述性统计
  20. CCSP2021 分赛区

热门文章

  1. PyTorch之前向传播函数自动调用forward
  2. iPhone 14 与iPhone 13
  3. TVM量化路线图roadmap
  4. 激光雷达Lidar Architecture and Lidar Design(下)
  5. 用户自定义协议client/server代码示例
  6. Dalvik虚拟机与java虚拟机的区别
  7. 2021年大数据Spark(二十八):SparkSQL案例三电影评分数据分析
  8. ERROR: Failed to resolve: com.android.support:appcompat-v7:29.0.0
  9. Java 二分法查找
  10. Failed to resolve:com.android.support:appcompat-v7:27.+