Python协程asyncio异步编程笔记分享
作者:季布, 发布时间:2022-03-05 22:23:31
目录
1.事件循环
2.协程和异步编程
2.1 基本使用
2.2 await
2.3 Task对象
1.事件循环
可以理解成为一个死循环,去检查任务列表中的任务,如果可执行就去执行,如果检查不到就是不可执行的,那就忽略掉去执行其他可执行的任务,如果IO结束了(比如说去百度下载图片,下载完了就会变成可执行任务)再去执行下载完成之后的逻辑
#这里的任务是有状态的,比如这个任务已经完成或者正在执行或者正在IO等待
任务列表 = [ 任务1, 任务2, 任务3,... ]
while True:
可执行的任务列表,已完成的任务列表 = 去任务列表中检查所有的任务,将'可执行'和'已完成'的任务返回
for 就绪任务 in 可执行的任务列表:
执行已就绪的任务
for 已完成的任务 in 已完成的任务列表:
在任务列表中移除 已完成的任务
如果 任务列表 中的任务都已完成,则终止循环
#在编写程序时候可以通过如下代码来获取和创建事件循环。
import asyncio
loop = asyncio.get_event_loop()
#将任务放到任务列表,让事件循环去检测任务的状态(是否可运行,是否IO)
loop.loop.run_until_complete(任务)
2.协程和异步编程
协程函数,定义形式为 async def 的函数。
协程对象,调用 协程函数() 所返回的对象。
# 定义一个协程函数
async def func():
pass
# 调用协程函数,返回一个协程对象(内部代码不会执行)
result = func()
2.1 基本使用
程序中,如果想要执行协程函数的内部代码,需要 事件循环 和 协程对象 配合才能实现
示例1:
import asyncio
async def func():
print("协程内部代码")
# 调用协程函数,返回一个协程对象。
result = func()
# 方式一
# loop = asyncio.get_event_loop() # 创建一个事件循环
# loop.run_until_complete(result) # 将协程当做任务提交到事件循环的任务列表中,协程执行完成之后终止。
# 方式二
# 本质上方式一是一样的,内部先 创建事件循环 然后执行 run_until_complete,一个简便的写法。
# asyncio.run 函数在 Python 3.7 中加入 asyncio 模块,
asyncio.run(result)
2.2 await
await+可等待对象(协程对象,Future,Task对象)
await是一个只能在协程函数中使用的关键字,用于遇到IO操作时挂起 当前协程(任务),当前协程(任务)挂起过程中 事件循环可以去执行其他的协程(任务),当前协程IO处理完成时,可以再次切换回来执行await之后的代码。
import asyncio
async def func():
print("执行协程函数内部代码")
# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。
# 当前协程挂起时,事件循环可以去执行其他协程(任务)。
#response是IO耗时结束后拿到的结果
response = await asyncio.sleep(2)
print("IO请求结束,结果为:", response)
result = func()
asyncio.run(result)
结果
执行协程函数内部代码
IO请求结束,结果为: None
#这里返回None表示这个好事没有啥意义,如果你是下载了一张图片成功后会返回一个结果
示例2:
import asyncio
async def others():
print("start")
await asyncio.sleep(2)
print('end')
return '返回值'
async def func():
print("执行协程函数内部代码")
# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
response = await others()
print("IO请求结束,结果为:", response)
asyncio.run( func() )
执行结果:
执行协程函数内部代码
start
end
IO请求结束,结果为: 返回值
示例3:
import asyncio
async def others():
print("start")
await asyncio.sleep(2)
print('end')
return '返回值'
async def func():
print("执行协程函数内部代码")
# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
#await等待有返回值才会向下执行
response1 = await others()
print("IO请求结束,结果为:", response1)
response2 = await others()
print("IO请求结束,结果为:", response2)
asyncio.run( func() )
执行结果:
执行协程函数内部代码
start
end
IO请求结束,结果为: 返回值
start
end
IO请求结束,结果为: 返回值
下一步依赖上一步的结果时使用await,但如果有其他任务依然会切换到其他任务去执行
2.3 Task对象
在事件循环中添加多个任务。
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。
除了使用 asyncio.create_task() 函数以外,还可以用低层级的 loop.create_task() 或 ensure_future() 函数。
不建议手动实例化 Task 对象。
本质上是将协程对象封装成task对象,并将协程立即加入事件循环,同时追踪协程的状态。
注意:asyncio.create_task() 函数在 Python 3.7 中被加入。
在 Python 3.7 之前,可以改用低层级的 asyncio.ensure_future() 函数。
示例1:
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return "返回值"
async def main():
print("main开始")
# 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
task1 = asyncio.create_task(func())
# 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
task2 = asyncio.create_task(func())
print("main结束")
# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。
# 此处的await是等待相对应的协程全都执行完毕并获取结果
ret1 = await task1
ret2 = await task2
print(ret1, ret2)
asyncio.run(main())
执行结果:
main开始
main结束
1
1
2
2
返回值 返回值
实例2:
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return "返回值"
async def main():
print("main开始")
# 创建协程,将协程封装到Task对象中并添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
# 在调用
task_list = [
asyncio.create_task(func(), name="n1"),
asyncio.create_task(func(), name="n2")
]
print("main结束")
# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。
# 此处的await是等待所有协程执行完毕,并将所有协程的返回值保存到done
# 如果设置了timeout值,则意味着此处最多等待的秒,完成的协程返回值写入到done中,未完成则写到pending中(比如下面的Timeout=1,要下载的图片是两秒,设为1秒就会执行失败,done内为空,而pending中就是执行失败的)。
done, pending = await asyncio.wait(task_list, timeout=None)
print(done, pending)
asyncio.run(main())
执行结果:
main开始
main结束
1
1
2
2
{
<Task finished name='n1' coro=<func() done, defined at C:/Users/xuan.li/Desktop/unidevopss/py3x64/ibuildmaster/apps/PROD/tests.py:513> result='返回值'>,
<Task finished name='n2' coro=<func() done, defined at C:/Users/xuan.li/Desktop/unidevopss/py3x64/ibuildmaster/apps/PROD/tests.py:513> result='返回值'>
}
set()
示例3:
import asyncio
async def func():
print("执行协程函数内部代码")
# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
response = await asyncio.sleep(2)
print("IO请求结束,结果为:", response)
coroutine_list = [func(), func()]
# 错误:coroutine_list = [ asyncio.create_task(func()), asyncio.create_task(func()) ]
# 此处不能直接 asyncio.create_task,因为将Task立即加入到事件循环的任务列表,
# 但此时事件循环还未创建,所以会报错。
# 使用asyncio.wait将列表封装为一个协程,并调用asyncio.run实现执行两个协程
# asyncio.wait内部会对列表中的每个协程执行ensure_future,封装为Task对象。
done,pending = asyncio.run( asyncio.wait(coroutine_list) )
来源:https://blog.csdn.net/weixin_47906106/article/details/120249639
猜你喜欢
- 一 概述在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章试图采用图文的方式来与大家一起探讨。“浅
- Memento备忘录模式 备忘录模式一个最好想象的例子:undo! 它对对象的一个状态进行了'快照', 在你需要的时候恢复原
- ppt要想完美的转pdf,图片,还是需要在windows下面来操作。1,安装python3.5.1下载地址Windows x86-64 ex
- SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo
- 前言我们在使用vue-cli启动项目的时候npm run dev便可以启动我们的项目了,通常我们的请求地址是以localhost:8080来
- 本文通过Python3+pyqt5实现了python Qt GUI 快速编程的19章的页面索引器应用程序例子。/home/yrd/eric_
- 在SQL查询分析器执行以下代码就可以了。01.declare @t varchar(255),@c varchar(255) 02.decl
- django处理Ajax跨域访问使用javascript进行ajax访问的时候,出现如下错误出错原因:javascript处于安全考虑,不允
- if (arr[i]){ &nb
- 如果管理网络设备很多,不可能靠人力每天去登录设备去查看是否在线。所以,可以利用python脚本通过每天扫描网络中的在线设备。可以部署在服务器
- 本文实例讲述了python实现一次创建多级目录的方法。分享给大家供大家参考。具体实现方法如下:import osos.makedirs( &
- 守护进程(daemon)是指在UNIX或其他多任务操作系统中在后台执行的电脑程序,并不会接受电脑用户的直接操控。此类程序会被以进程的形式初始
- 写在前面 最近和几个小伙伴们在写字节跳动第五届青训营后端组的大作业。虽然昨天已经提交了项目,但有很多地方值得总结一下,比如这一篇,
- 前言有时候我们需要把图片填充成某个数字的整数倍才能送进模型。例如,有些模型下采样倍率是8倍,或者16倍,那么输入的长和高就分别应该是8或16
- tf.reverse_sequence()简述在看bidirectional_dynamic_rnn()的源码的时候,看到了代码中有调用 r
- 一、介绍在做YOLOv3项目时,会需要将文本文件中的某部分内容进行批量替换和修改,所以编写了python程序批量替换所有文本文件 * 定部分的
- 本文实例讲述了MYSQL锁表问题的解决方法。分享给大家供大家参考,具体如下:很多时候!一不小心就锁表!这里讲解决锁表终极方法!案例一mysq
- 因为刚学vue然后自己自习了一下axios,然后想写一个简单的查询后台数据<tr v-for=" user in uList
- 本文实例为大家分享了Python编写车票订购系统,Python实现快递收费系统的具体代码,供大家参考,具体内容如下要求:1.上网查询郑州到北
- 本文实例讲述了php实现搜索一维数组元素并删除二维数组对应元素的方法。分享给大家供大家参考。具体如下:定义一个一维数组一个二维数组如下$fr