異步編程 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

相關文章
相關標籤/搜索