asyncio.sleep
协程对象来执行
import asyncio
import time
async def coro_test():
print(time.time())
async def say_after(delay, what):
# await coro_test()
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')
await say_after(2, 'world')
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
运行逻辑:
1, asyncio.run(main()) 启动一个事件循环,将入口点main()协程对象传入,生成一个对应的任务task_main 。
2,事件循环运行任务task_main,然后执行main()第1条代码:print(f"started at {time.strftime(‘%X’)}") 。
3,接着执行main()第2条代码:await say_after(1, ‘hello’),
第2条代码首先生成一个say_after(1, ‘hello’)协程对象,同时生成该协程对象对应的 task_1 。
(在执行await语句时, 会交回控制权)
await语法,task_main任务将控制权返回给事件循环,同时告诉事件循环需要等待 task_1 才能继续运行。
4,事件循环获得控制权后,发现此时有两个任务task_main和 task_1,同时task_main在等待 task_1,
于是会去执行 task_1任务 。
5,task_1任务将执行第1条代码:await asyncio.sleep(1),同样会生成 asyncio.sleep(1) 协程对象 (asyncio.sleep 也是一个coroutine),生成对应的任务task_2,此时 await语句 将控制权返回给事件循环 。
6 ,事件循环获得控制权后,发现此时有三个任务 task_main、task_1、task_2,由于task_main、task_1都处于等待状态,于是执行 task_2 。
7,task_2在1秒后运行完成,返回控制权给事件循环 。
8,事件循环获得控制权,发现此时有两个任务 task_main 和 task_1,同时 task_main 在等待 task_1,
于是会去执行task_1任务 。
9,task_1任务执行第2条代码:print(‘hello’),执行完成后,任务也运行结束,将控制权返回给事件循环;
10,事件循环获得控制权后,发现此时有一个任务task_main,于是接着执行下一条代码:await say_after(2, ‘world’),继续重复上述过程 。
event loop不能强行从一个task拿回控制器,需要task主动的把控制器交回去,交回的方式一种是 await , 一种是函数执行完成
asyncio.sleep 与 asyncio.create_task(asyncio.sleep())
先看两段代码
import asyncio
async def main():
await asyncio.create_task(asyncio.sleep(0.5))
asyncio.run(main())
import asyncio
async def main():
await asyncio.sleep(0.5)
asyncio.run(main())
使用 viztracer 工具看一下, 工具地址
可以看到 main函数是直接调用了 asyncio.sleep,说明 await coroutine 时, 并没有将await 变成一个 task
(网上是有一些文章说是await asyncio.sleep 时会把它变成一个task)
当在一个task中 await coroutine 的时候, 这个task 并不会交出控制权, 会调用这个coroutine
就像调用一个生成器一样, 等coroutine返回。(asyncio.sleep 源码中是新建了一个future)
这样也是上面第6步的 task_main、task_1都处于等待状态, 执行task_2的原因。