本文是我在学习过程中记录学习的点点滴滴,目的是为了学完之后巩固一下顺便也和大家分享一下,日后忘记了也可以方便快速的复习。
async和await
前言
今天学习的主要是关于async、await知识的理解和应用
关于线程、进程和协程的理解之前这篇文章已经讲过,不懂的或忘记了可以点击这篇文章线程、进程和协程详解复习
import asyncio
import time
async def async_hello_world():
now = time.time() #(1)
await asyncio.sleep(1) #(2)
print("1",time.time() - now) #(3)
print("000Hello, world!") #(4)
await asyncio.sleep(1) #(5)
print("2",time.time() - now) #(6)
print("000000Hello, world!") #(6)
async def main():
await asyncio.gather( #(A)
async_hello_world(), #(B)
async_hello_world()) #(C)
print("Hello, world!1111")
now = time.time() #全局时间起点
# run 2 async_hello_world() coroutine concurrently
asyncio.run(main()) #启动事件循环
#输出结果:
1 1.0058016777038574
000Hello, world!
1 1.0058016777038574
000Hello, world!
2 2.012509822845459
000000Hello, world!
2 2.012509822845459
000000Hello, world!
Hello, world!1111
详细步骤解释
阶段 1:初始化
全局时间起点
now = time.time() 记录程序开始运行的初始时间(记为 T0)。
启动事件循环
asyncio.run(main()) 创建事件循环并运行 main() 协程。
创建协程任务
asyncio.gather() 在 main() 中启动 2 个 async_hello_world 协程(记为协程1、协程2)。
此时,2 个协程被加入事件循环的任务队列,但尚未执行。
阶段 2:协程并发执行(体现异步性)
协程1、2开始执行
事件循环依次调度每个协程执行到第一个 await 点:
每个协程执行步骤 (1) now = time.time()(每个协程的 now 是独立的局部变量)。
执行到步骤 (2) await asyncio.sleep(1),协程挂起(直接挂起执行下一步,无需等待),将控制权交还事件循环。
此时:
所有 2 个协程均处于 asyncio.sleep(1) 的挂起状态。
事件循环开始等待 1 秒的睡眠完成。
阶段 3:第一次睡眠完成(体现async内部的同步性)
1 秒后(≈T0+1)
所有 2 个协程的 asyncio.sleep(1) 同时完成,事件循环恢复它们的执行。
协程恢复顺序
事件循环会按任务就绪顺序恢复协程(通常是先进先出,但具体顺序可能因实现而异)。
每个协程依次执行:
步骤 (3):打印 1 和耗时(≈1秒)。
步骤 (4):打印 Hello, world!。
执行到步骤 (5) await asyncio.sleep(1),协程再次挂起。
此时输出:
1 1.0058016777038574
000Hello, world!
1 1.0058016777038574
000Hello, world!
注意:输出顺序可能因协程调度顺序而不同,但时间差接近 1 秒。
阶段 4:第二次睡眠完成
再过 1 秒(≈T0+2)
所有协程的 asyncio.sleep(1) 再次完成,事件循环恢复执行。
协程恢复顺序
类似第一次恢复,每个协程依次执行步骤 (6):打印 2 和总耗时(≈2秒)。
输出结果:
2 2.012509822845459
000000Hello, world!
2 2.012509822845459
000000Hello, world!
阶段 5:在async def main忠等待await语句执行完毕,然后继续执行下一条语句(体现同步性)
Hello, world!1111
总结:
async只是定义了一个协程,在协程里面可以使用await,在里面所有使用了await的语句都可以同时运行,因为他们执行完无需等待返回结果就会让出控制权以便执行其他任务,这个await里面的事件不会按照同步顺序一样执行,在执行一个事件之后这个事件可能要等服务器返回数据(基本上丢进来的事件都是IO事件,基本上都会需要等待一小会返回数据)但是在等待返回数据这段时间,在await里面的事件不需要等待,CPU空闲了会自动找下一个事件执行,如果在外面(没有await定义的语句)那么需要等上个语句返回结果彻底执行完才会继续执行下一个语句,这就是最大的区别,这就是异步与同步。另外async定义的事件就是一个协程,上述代码就凸显了代码的同步性执行顺序,以及协程里面await语句的异步性。
💕 原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
👍 点赞,你的认可是我创作的动力! \textcolor{orange}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
⭐ 收藏,你的青睐是我努力的方向! \textcolor{red}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
🥕 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!