【Python基础】线程

文章目录

    • @[toc]
      • 线程与进程的区别与联系
      • 同步任务
        • 示例
      • 并发任务
        • 示例
      • 线程方法
        • `thread_object.start()`
        • `thread_object.join()`
        • `thread_object.setDaemon()`
        • `thread_object.current_thread()`

线程与进程的区别与联系

  • 线程是可以被计算机CPU调度的最小单元
  • 进程是计算机分配资源(CPU、内存等)的最小单元
  • 一个进程中至少有一个线程,同一个进程中的线程共享进程中的资源

同步任务

  • 我们在此之前编写的代码都是同步代码,代码从上到下按顺序执行,如果前一个任务没有完成,那么不能运行之后的任务
示例
import timedef work_1():print('任务1...')time.sleep(2)def work_2():print('任务2...')time.sleep(2)start = time.time()work_1()
work_2()end = time.time()print(f'总共用时: {end - start} s')
任务1...
任务2...
总共用时: 4.020084857940674 s
  • 可以看到整个程序用时 4 4 4秒,work_2()需要等待work_1()运行结束后才能运行

并发任务

  • 使用线程来运行上面的代码,能够优化运行时间
示例
import time
import threadingdef work_1():print('任务1...')time.sleep(2)def work_2():print('任务2...')time.sleep(2)# 通过 Thread 类创建线程对象, 并使用 target 绑定线程对象要运行的任务
t1 = threading.Thread(target=work_1)
t2 = threading.Thread(target=work_2)# 运行线程
start = time.time()t1.start()
t2.start()t1.join()
t2.join()end = time.time()print(f'总共用时: {end - start} s')
任务1...
任务2...
总共用时: 2.0165793895721436 s
  • 可以看到整个程序用时 2 2 2秒,work_1()work_2并发运行

  • 下面的示例可以看到CPU调度线程时的“随机性”

import time
import threadingdef work_1():for i in range(5):print('任务1...')time.sleep(2)def work_2():for i in range(5):print('任务2...')time.sleep(2)t1 = threading.Thread(target=work_1)
t2 = threading.Thread(target=work_2)t1.start()
t2.start()
任务1...
任务2...
任务2...任务1...任务1...任务2...任务2...
任务1...
任务2...
任务1...
  • 可以看到任务 1 1 1和任务 2 2 2的调度顺序是我们无法确定的,是由CPU的调度算法决定的

线程方法

  • 在学习线程方法之前,我们需要知道Python程序是如何被运行的
    • 一个Python文件被解释器运行时会在操作系统中创建一个进程
    • 然后该进程会创建一个线程来运行文件中的代码,这个程序最初创建的线程称为主线程
    • 当主线程执行到t = threading.Thread()时会创建一个新的线程,称为子线程
    • 当前进程中的主线程与子线程由CPU进行调度,并发地运行,具体调度哪个线程由操作系统的调度算法决定
    • 子线程在运行时,主线程不会等待子线程,而是继续向下执行,直到执行到文件末尾没有代码时,主线程会等待子线程运行结束后再退出
thread_object.start()
  • t = threading.Thread()只是创建了一个线程,并不会执行线程代码

  • t.start()使线程t达到就绪态,等待CPU进行调度,具体何时调度由CPU决定

  • 以上面的并发任务的代码为例,先注释掉t1.start()t2.start()

import time
import threadingdef work_1():print('任务1...')time.sleep(2)def work_2():print('任务2...')time.sleep(2)# 通过 Thread 类创建线程对象, 并使用 target 绑定线程对象要运行的任务
t1 = threading.Thread(target=work_1)
t2 = threading.Thread(target=work_2)# 运行线程
start = time.time()t1.start()
t2.start()# t1.join()
# t2.join()end = time.time()print(f'总共用时: {end - start} s')
任务1...
任务2...
总共用时: 0.0009987354278564453 s
  • 可以看到主线程没有等待子线程,而是继续向下执行
  • 当执行到end = time.time()时,此时end记录的时间是主线程运行到这行代码的时间
  • 之后运行print(f'总共用时: {end - start} s'),输出时间0.0009987354278564453 s,此时执行到了文件末尾没有其他代码,主线程会等待子线程运行结束后再退出
  • 为了能正确记录线程运行的时间,我们需要让主线程等待子线程
thread_object.join()
  • t.join()使主线程等待子线程,子线程任务执行结束后主线程再继续向下执行
  • 仍然以上面的并发任务的代码为例,取消注释t1.start()t2.start()
import time
import threadingdef work_1():print('任务1...')time.sleep(2)def work_2():print('任务2...')time.sleep(2)# 通过 Thread 类创建线程对象, 并使用 target 绑定线程对象要运行的任务
t1 = threading.Thread(target=work_1)
t2 = threading.Thread(target=work_2)# 运行线程
start = time.time()t1.start()
t2.start()t1.join()
t2.join()end = time.time()print(f'总共用时: {end - start} s')
任务1...
任务2...
总共用时: 2.008962392807007 s
  • 可以看到主线程等待子线程运行结束后才继续向下执行,正确记录了子线程运行的时间
thread_object.setDaemon()
  • 设置守护线程,需要在线程启动之前进行设置
  • 如果一个线程是守护线程,那么主线程运行结束后不论子线程任务是否结束都会自动退出
  • 没有设置守护线程的情况
import time
import threadingdef work():for i in range(5):print(i)time.sleep(1)t = threading.Thread(target=work)
# t.setDaemon(True)t.start()print('主线程即将退出...')
0
主线程即将退出...
1
2
3
4
  • 设置守护线程的情况
import time
import threadingdef work():for i in range(5):print(i)time.sleep(1)t = threading.Thread(target=work)
t.setDaemon(True)t.start()print('主线程即将退出...')
0
主线程即将退出...
  • 可以看到并没有继续输出 1 1 1 2 2 2 3 3 3 4 4 4,主线程就退出了
thread_object.current_thread()
  • 获取当前线程对象的引用
  • 可以用来获取线程名称
import threadingdef work():name = threading.current_thread().name  # getName()print(name)for i in range(5):t = threading.Thread(target=work)t.name = f'线程-{i}'  # setName(f'线程-{i}')t.start()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/223245.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

和利时DCS数据采集

在工业自动化领域,和利时DCS(分布式控制系统)被广泛应用,它对于工厂的生产过程和设备管理起到了重要的作用。然而,对于和利时DCS数据的采集,很多工厂面临着一些难点。本文将介绍和利时DCS的概述&#xff0c…

C语言—每日选择题—Day42

第一题 1. 下面程序输出的结果是&#xff08;&#xff09; #include <stdio.h> int main () {int x;x printf("I See, Sea in C");printf("x%d" , x); } A&#xff1a;2 B&#xff1a;随机值 C&#xff1a;都不是 D&#xff1a;15 答案及解析 D p…

智慧港口解决方案:PPT全文69页,附下载

关键词&#xff1a;智慧港口解决方案&#xff0c;数字化港口&#xff0c;智慧港口发展现状与展望&#xff0c;智慧码头&#xff0c;智慧港口发展趋势 一、智慧港口建设背景 随着数字经济、智慧交通发展&#xff0c;强调“要大力发展智慧交通和智慧物流”“努力打造世界一流的…

LAMP与LNMP架构

目录 一、概述 二、各组件的主要作用 一. 编译安装Apache httpd服务 二. 编译安装mysqld 服务 三. 编译安装PHP 解析环境 四. 安装论坛 LNMP架构 一、编译安装Nginx 二、编译安装MySQL服务 三、安装配置php文件 四、部署论坛 扩展 fpm参数优化 一、概述 LAMP架构是…

TCP/IP详解——UDP 协议

文章目录 1. UDP1.1 UDP 头部1.2 UDP 校验和1.3 UDP 传输过程1.4 UDP-Lite1.5 最大 UDP 数据报长度1.6 UDP 输入队列 1. UDP UDP&#xff1a;用户数据报协议&#xff08;User Datagram Protocol&#xff09;面向无连接的&#xff0c;也就是无需建立连接&#xff0c;传输不可靠。…

成绩分析。

成绩分析 题目描述 小蓝给学生们组织了一场考试&#xff0c;卷面总分为 100分&#xff0c;每个学生的得分都是一个0到100的整数。 请计算这次考试的最高分、最低分和平均分 输入描述 输入的第一行包含一个整数n(1n104)&#xff0c;表示考试人数。 接下来n行&#xff0c;每行包含…

K8S 常用命令

获取所有的pod资源&#xff1a; kubectl get pod 获取所有的命名空间&#xff1a; kubectl get namespace 获取所有的Deployment资源&#xff1a; kubectl get deployment 删除指定的deploy: kubectl delete deploy nginx 获取所有的服务&#xff1a; kubectl get serv…

用liblas将点云写入las文件

用liblas将点云写入las文件 首先配置liblas库&#xff0c;可以见上一篇博客 inline int writeLas(string lasPath, Points3Ds pt3Ds) {//point3ds是我自己定义的结构std::ofstream ofs;ofs.open(lasPath, std::ios::out | std::ios::binary);if (!ofs.is_open()) {std::cerr …

宏景eHR SQL 注入漏洞复现(CVE-2023-6655)

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合,满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR 中发现了一种被分类为关键的漏洞,该漏洞影响了Login Interface组件中/w_selfservice/oauthservlet/%2e../.%2e/genera…

C#随笔 | List.Sort()使用小计

1、使用List.Sort()对基本数值类型数据进行排序 案例&#xff1a;对存放int数据的List进行排序 其实C#中的List的Sort函数中的比较函数CompareTo有三种结果 1, -1 ,0分别代表大&#xff0c;小&#xff0c;相等。默认List的排序是升序排序。 举个例子&#xff1a;在比较函数Co…

ICV:2023 年上半年全球量子计算的进展

​ 2023年上半年&#xff0c;量子计算&#xff08;QC&#xff09;领域取得了一系列重要进展和突破&#xff0c;显示出量子计算技术的快速发展和商业应用的不断拓展。本报告从制度进步、产业生态、投融资形势、总结与展望四个方面对量子计算领域进行了系统而详细的分析。报告不仅…

You cannot access body after reading from request‘s data stream 处理办法

参考&#xff1a; https://blog.csdn.net/qq_33036061/article/details/109528061 https://www.dmge.cn/article/1028 这个错误的原因是&#xff0c;当你从 request.body 中读取数据时&#xff0c;Django 会把数据流的指针移动到数据流的末尾。这意味着你不能再次从数据流中读…

每天一点python——day94

#每天一点Python——94 #面向对象的三大特征——封装 封装&#xff1a;隐藏内部细节&#xff0c;对外提供操作方式。【提高程序的安全性】 继承&#xff1a;在函数调用时&#xff0c;使用’形参名称值‘的方式进行传参&#xff0c;传递参数的顺序可以与定义时参数顺序不同【提高…

push和扩展运算符...引发的问题

文章目录 一、问题二、原因三、解决3.1、使用拓展运算符...合并&#xff08;推荐使用&#xff09;3.2、使用concat合并3.3、循环push 四、最后 一、问题 const items [] const newItems new Array(1000000) items.push(...newItems)上面代码会出现如下错误&#xff1a; Unc…

从零开始搭建企业管理系统(七):RBAC 之用户管理

RBAC 之用户管理 创建表&#xff08;Entity&#xff09;用户表角色表权限表用户角色表关系注解ManyToMany 角色权限表 接口开发UserControllerUserServiceUserServiceImplUserRepository 问题解决update 更新问题懒加载问题JSON 循环依赖问题 根据上一小结对表的设计&#xff0…

逻辑回归正则化

逻辑回归正则化在处理具有多个特征且特征可能共线性&#xff08;即特征之间高度相关&#xff09;的数据集特别有用。 下面用一个例子说明什么是正则化&#xff1a; 假设你在厨房准备一顿饭&#xff0c;你的目标是做出美味又不过分油腻的菜肴。 没有正则化的情况&#xff1a;…

【面试】测试/测开(NIG2)

145. linux打印前row行日志 参考&#xff1a;linux日志打印 前10行日志 head -n 10 xx.log后10行日志 tail -n 10 xx.log tail -10f xx.log使用sed命令 sed -n 9,10p xx.log #打印第9、10行使用awk命令 awk NR10 xx.log #打印第10行 awk NR>7 && NR<10 xx.log …

OTP语音芯片与可重复擦写(Flash型)语音芯片:特性比较与应用差异

在嵌入式语音应用中&#xff0c;OTP&#xff08;一次性可编程&#xff09;语音芯片与可重复擦写&#xff08;Flash型&#xff09;语音芯片是两种常见的存储解决方案&#xff0c;它们在特性和应用上存在明显差异。本文将深入比较唯创知音这两类语音芯片的区别&#xff0c;以帮助…

OpenCV图像处理——Python开发中OpenCV视频流的多线程处理方式

前言 在做视觉类项目中&#xff0c;常常需要在Python环境下使用OpenCV读取本地的还是网络摄像头的视频流&#xff0c;之后再调入各种模型&#xff0c;如目标分类、目标检测&#xff0c;人脸识别等等。如果使用单线程处理&#xff0c;很多时候会出现比较严重的时延&#xff0c;…

H3C ER G2系列路由器信息泄露漏洞

H3C ER G2系列路由器信息泄露漏洞 免责声明漏洞描述漏洞影响漏洞危害漏洞页面漏洞复现1. 构造poc2. 发生数据包&#xff0c;获取密码3. 登录系统 免责声明 仅用于技术交流,目的是向相关安全人员展示漏洞利用方式,以便更好地提高网络安全意识和技术水平。 任何人不得利用该文章…