1、asyncio
import asyncio
# coroutine function: async开头的函数
async def main():
    print('hello')
    await asyncio.sleep(1)
    print('world')
coro = main()  # coroutine object:协程对象
# 当生成协程对象的时候,并不运行函数里面的程序。
# 运行时需要两步走:进入 async 模式、把coroutine变成task
asyncio.run(coro)  # 创建 event loop 来跑 task2、了解 await 作用
import asyncio
import time
async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)
async def main():
    print(f"started at {time.strftime('%X')}")
    await say_after(1, 'hello')  # await 把控制权交还给 event loop
    await say_after(2, 'world')
    print(f"finished at {time.strftime('%X')}")  # 总共花了3秒
coro = main()  # coroutine object:协程对象
asyncio.run(coro)  # 创建 event loop 来跑 task 
 
3、了解 asyncio.create_task
import asyncio
import time
async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)
async def main():
    
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))
    # create_task 可提前创建好 task
    # 到目前为止,两个 task 都已初始化到 event loop 里面了
    print(f"started at {time.strftime('%X')}")
    await task1
    await task2
    print(f"finished at {time.strftime('%X')}")
'''
task1 执行1s等待的时候,event loop 是空闲的,
它发现 task2 可以执行,就执行了一秒task2,
所以当 task1 执行完之后,task2 还剩下1秒等待需要执行,所以总体时间花了2秒
async 很适合解决网络通讯的问题,因为网络通讯很多时间是在等待上的,也就是所谓的 io bound task。
等待的时间,可以去完成别的 task
'''
asyncio.run(main())

4、协程返回值怎么获取?
import asyncio
import time
async def say_after(delay, what):
    await asyncio.sleep(delay)
    return f"{what} - {delay}"
async def main():
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))
    print(f"started at {time.strftime('%X')}")
    ret1 = await task1  # 拿到返回值
    ret2 = await task2
    print(ret1)
    print(ret2)
    print(f"finished at {time.strftime('%X')}")
asyncio.run(main())5、了解 asyncio.gather
import asyncio
import time
async def say_after(delay, what):
    await asyncio.sleep(delay)
    return f"{what} - {delay}"
async def main():
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))
    print(f"started at {time.strftime('%X')}")
    # asyncio.gather的参数可以是若干个协程对象,task,以及asyncio.gather的返回值
    # 如果参数是协程对象,它会自动给转化为task
    # 最终返回一个list:['hello - 1', 'world - 2']
    ret = await asyncio.gather(task1, task2)
    print(ret)
    print(f"finished at {time.strftime('%X')}")
asyncio.run(main())6、了解 asyncio.gather 之后优化一下代码
import asyncio
import time
async def say_after(delay, what):
    await asyncio.sleep(delay)
    return f"{what} - {delay}"
async def main():
    print(f"started at {time.strftime('%X')}")
    # 直接将协程对象放到 asyncio.gather 中,它会自动变为 task,再逐个 await,
    # 最后返回一个列表式的结果:['hello - 1', 'world - 2']
    # 协程的意义:同一时间只有一个任务在跑,它只是想办法充分利用中间的等待时间
    # 协程对象只有变成了 task 才能被执行,
    # 而 await 和 gather 都是隐式地将协程对象变成了 task
    ret = await asyncio.gather(
        say_after(1, 'hello'),
        say_after(2, 'world')
    )
    print(ret)
    print(f"finished at {time.strftime('%X')}")
asyncio.run(main())


















