浅析Python中线程以及线程阻塞
作者:真的不能告诉你我的名字 发布时间:2022-03-06 22:14:23
本文所依赖的环境为:
进程和线程的概念
进程概念
我们想运行一个程序,首先会将该程序从存储介质上通过IO
总线加载进内存中,而后再通过cpu
进行调度。这个时候,我么么将这个正在运行的程序称之为进程,它有内存地址、内存空间、数据栈等等信息,进程之间通信一般称之为IPC
,常见的方法有 管道、消息队列、套接字等。
线程概念
而线程则不同,线程是在进程中运行的,一个进程至少有一个线程。在单个cpu
中,同一时刻一个进程只有一个线程在工作,其他则被挂起,也称之为睡眠。由于线程属于进程,所以会共享进程的内存信息。线程之间通信不仅可以使用共享内存来通信,依然可以使用 如 管道、消息队列、套接字等。
线程优缺点
多线程是一种并发方式,优点为可以同时执行多个任务,用于提升时间和效率。
比如,我们想写一个python
服务器下载电影,一次只能下载一部,若我们使用多线程后,可以一次"同时"下载n
部,从而提升了效率。
但是有些事多线程不能做的,并发冲突是其中一种。比如掘金点赞功能,如果没有对点赞这个变量进行并发控制,可能会出现数据不一致的情况。
在python中如何使用线程
在使用python
写多线程之前,先来看一个小案例,假设我们使用python
写了一个下载电影的程序。
import time
def downloadMovie(i):
print("%s 开始下载编号为%s电影中。。。" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), str(i)))
time.sleep(5)
print("%s 编号为%s电影下载完毕" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), str(i)))
def main():
for i in range(5):
downloadMovie(i)
if __name__ == '__main__':
main()
我们假设模拟下载电影的一个程序,下载过程使用time.sleep
代替。在没有使用多线程的时候,它的执行过程如下:
可以看到,它是顺序执行的,需要等上一部下载完毕,才能开始下载下一部。
如果使用线程来做该需求呢? 我们可以这样来写:
import time
import threading
def downloadMovie(i):
print("%s 开始下载编号为%s电影中。。。" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), str(i)))
time.sleep(5)
print("%s 编号为%s电影下载完毕" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), str(i)))
def main():
for i in range(5):
t = threading.Thread(target=downloadMovie,args=(i,))
t.start()
if __name__ == '__main__':
main()
上述代码,在原始代码基础上,我们引入了threading
库,在循环中使用Thread
来做线程的实例化对象,我们需要传入target
和args
,target
需要传入函数名称,args
需要传入参数,注意这里参数需要传入可迭代的对象,所以当只有一个参数的时候,也需要在后面加一个,
。最后使用start
方法让其开始执行。
运行后的效果如下:
可以发现,我们程序几乎同步的打印下载开始,也几乎同时打印下载完毕。
总结起来发现,我们线程启动一个线程,是不是非常简单呢?只需要引入threading
模块,定义Thread
来做对象,最后使用start()
运行即可。
线程阻塞也很重要
线程直接跑就完了呗,为什么还需要阻塞呢?我们这里做一个简单的需求:上面的代码改改,我们下载完视频后,要压缩一下,由于只讨论线程,所以就只用print
代替操作,我们可以这样操作:
在上面的基础上,我们增加了2个步骤,1: 是将下载好的文件放入列表fileList
中,2. 最后开始遍历fileList
文件,进行压缩,最后打印一个压缩完毕,看起来没什么问题吧?
那我们来运行一下一下呢?
额。。。这个很显然不符合我们的预期,我们还没下载文件完毕,怎么就开始压缩了呢,而且压缩完毕了,再输出的文件下载完毕,这是为什么呢?
这是因为线程在启动后,如果我们不去设置阻塞,他就会一直执行下去,就拿我们刚才的案例来看,我们可以将其理解为:
看上图,我们启动线程后,它就放在后台了,我们就立马执行遍历fileList
步骤,但是这个时候恰恰fileList
是空的,所以我们压缩了空文件,压缩完毕后,文件才下载完毕。
这个时候我们就需要等线程执行完毕之后,再执行下面的语句了,否则执行完了没意义,所以这个时候就需要引入线程阻塞了,我们需要将下载的线程全部执行完毕后,再开始压缩文件,只需要线程增加一个join
方法即可,代码修改如下:
在原先的基础上,我们需要先定义一个线程池,用于放已经执行了的线程,而后再遍历该线程池,每一个都设置阻塞,这样就会等所有线程都执行完毕了,再进行后面的操作,由于我们后面是压缩需要用到前面的结果,所以阻塞是必不可少的,程序执行结果为:
这个流程图可以理解为这样的:
现在你知道阻塞有什么用了吧。
来源:https://juejin.cn/post/7224874901815492668


猜你喜欢
- 今天展示一个利用pandas将json数据导入excel例子,主要利用的是pandas里的read_json函数将json数据转化为data
- 主函数(Main Function)是程序中最重要的部分之一,它是程序入口点,也是程序开始执行的地方。1、主函数的定义在 Python 中,
- github源码地址:https://github.com/kuishou68/python各类图表的实现效果爬取的说说内容个性化说说内容词
- 说到转置操作,顺便提及矩阵与数组的区别:矩阵:数学里的概念,其元素只能是数值,这也是区别于数组的根本所在数组:计算机中的概念,代表一种数据组
- 我其实是同一天看到Robert Treat几人整理的”Mysql 迁移到Oracle前需要了解的50件事“与Baron Schwartz的”
- MySQL是支持在单个查询字符串中指定多语句执行的,使用方法是给链接指定参数: //链接时设定 mysql_real_connect( ..
- 实现图形校验和单点登录效果图前置条件学习一下 nest安装新建项目npm i -g @nestjs/cli nest new project
- 前言:md5解密,百度了一下发现教程不是很多也不详细。这个图都没一张。。。0x01windows环境,kali也可以啊burpsuitere
- 众所周知IE6不支持position:fixed,这个bug与IE6的双倍margin和不支持PNG透明等bug一样臭名昭著。前些天我做自己
- scikit-learn库scikit-learn已经封装好很多数据挖掘的算法现介绍数据挖掘框架的搭建方法1.转换器(Transformer
- 一、图例(legend)import plotly.io as pioimport plotly.express as pximport p
- 引言pymysqlpool (本地下载)是数据库工具包中新成员,目的是能提供一个实用的数据库连接池中间件,从而避免在应用中频繁地创建和释放数
- python PIL图像处理模块中的ImageDraw类支持各种几何图形的绘制和文本的绘制,如直线、椭圆、弧、弦、多边形以及文字等。下面直接
- mysql中文排序方法1 mysql在查询字符串时是大小写不敏感的,在编绎mysql时一般以ISO-8859字符集作为默认的字符集,因此在比
- 描述给ChatGPT的描述内容:python在桌面上显示动态的文字,不要显示窗口边框。窗口背景和标签背景都是透明的,但标签内的文字是有颜色。
- 作用说明该方法被用于绘制关键点的匹配情况。我们看到的许多匹配结果都是使用这一方法绘制的——一左一右两
- 本文实例总结了python选择排序算法。分享给大家供大家参考。具体如下:代码1:def ssort(V):#V is the list to
- 在VirtualBox中使用Ubuntu虚拟机中,会出现虚拟硬盘不够用的情况:查了一下磁盘空间,如下所示:df -H启动CMD命令行,进入V
- 实现思路将视频(MP4 等)转换为 M3U8 视频的服务,可以按照以下步骤进行操作:将视频(MP4 等)转换为 M3U8:在服务中,使用适当
- 前言ThinkPHP出于安全的考虑增加了表单令牌Token,由于通过Ajax异步更新数据仅仅部分页面刷新数据,就导致了令牌Token不能得到