异步编程 101:asyncio中的 for 循环

前面写的异步编程的几篇文章:编程

废话很少说,上代码:bash

这个代码只适用于Python3.7,由于asyncio.run()在 Python3.7才提出微信

import asyncio

async def heavy_task():
    await asyncio.sleep(2)

async def main():
    for _ in range(100):
        await heavy_task()

if __name__ == '__main__':
    asyncio.run(main())
复制代码

请问上面这个代码须要多久完成?答案是20秒,而不是咱们指望的那样在2秒内完成。session

理解缘由须要先搞明白await到底干了什么:事件循环执行到await的时候,会把当前的协程挂起(暂停),而后看看当前的事件循环池里面有哪些其余能够执行的协程,接着继续执行其余的协程。app

main()中的 for 循环是一个总体,await heavy_task()会把整个 main() 挂起,等到await的heavy_task()执行完了(也就是两秒后),接着再返回main(),从上次落下的地方继续。而上次落下的地方,仍是在这个 for 循环里面的。异步

因此,这个程序是异步的吗?能够确定的说是的,针对整个程序是异步的。可是对于main(),它的for循环仍是阻塞的。async

上述问题的根源在于:咱们没能及时往事件循环里面添加协程for 循环要等到heavy_task()结束了再建立下一个协程。要解决这个能够用asyncio.gather()异步编程

前面一篇文章里面咱们的那个代码:先把全部的协程事先建立好,而后一次性交给asyncio.gather()oop

import time
import asyncio
import aiohttp

async def fetch_async(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            status_code = resp.status
            print(status_code)


async def visit_async():
    start = time.time()
    tasks = []
    for _ in range(100):
        tasks.append(fetch_async(URL))
    await asyncio.gather(*tasks)
    end = time.time()
    print("visit_async tasks %.2f seconds" % (end - start))


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(visit_async())
复制代码

若是你像我同样真正热爱计算机科学,喜欢研究底层逻辑,欢迎关注个人微信公众号:post

相关文章
相关标签/搜索