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

标签:Python,协程,asyncio,异步编程
0
投稿

猜你喜欢

  • 使用python+pandas读写xlsx格式中的数据

    2023-03-25 00:55:16
  • 通过Python pyecharts输出保存图片代码实例

    2021-09-14 22:26:11
  • 常用的javascript设计模式

    2023-08-18 06:54:27
  • 如何将python文件打包成exe可运行文件

    2022-06-29 19:01:17
  • Python-openCV开运算实例

    2022-06-18 18:53:35
  • Go中如何使用set的方法示例

    2024-04-28 10:47:19
  • pytorch实现focal loss的两种方式小结

    2023-07-02 14:43:22
  • MySQL特定表全量、增量数据同步到消息队列-解决方案

    2024-01-24 04:36:47
  • python中pylint使用方法(pylint代码检查)

    2023-10-28 09:41:52
  • 在ASP.NET 2.0中操作数据之四十六:使用SqlDataSource控件检索数据

    2023-07-04 14:31:37
  • tensorflow学习教程之文本分类详析

    2023-10-18 17:56:40
  • python3+PyQt5+Qt Designer实现堆叠窗口部件

    2023-12-30 01:21:55
  • python学生管理系统开发

    2022-05-20 23:00:00
  • ES6/JavaScript使用技巧分享

    2024-04-30 10:10:04
  • 轻松掌握执行一个安全的SQL Server安装

    2009-01-13 14:03:00
  • python3实现TCP协议的简单服务器和客户端案例(分享)

    2023-01-11 13:11:21
  • win2003安装sqlserver 2000提示无法验证产品密钥的解决方法

    2024-01-27 00:18:39
  • mysql创建数据库,添加用户,用户授权实操方法

    2024-01-14 18:16:58
  • 10个ASP网页制作技巧

    2007-09-24 13:12:00
  • yolov5训练时参数workers与batch-size的深入理解

    2021-08-01 04:50:20
  • asp之家 网络编程 m.aspxhome.com