Python3.7 高級編程之 async/await asyncio 事件循環的使用

什麼是事件循環:
事件循環是每個 asyncio 應用的核心。 事件循環會運行異步任務和回調,執行網絡 IO 操作,以及運行子進程。
說簡單點就是由於python是單線程的 程序在執行中會將所有任務放到隊列中去逐一執行,當發現阻塞時就去執行其他任務,知道程序結束。
應用開發者通常應當使用高層級的 asyncio 函數,例如 asyncio.run(),應當很少有必要引用循環對象或調用其方法。

主要方法介紹:
asyncio.get_running_loop():返回當前 OS 線程中正在運行的事件循環。如果沒有正在運行的事件循環則會引發 RuntimeError。 此函數只能由協程或回調來調用。
asyncio.get_event_loop():獲取當前事件循環。如果當前OS線程中沒有設置當前事件循環,則OS線程是主線程,並且尚未調用set_event_loop(),asyncio將創建一個新的事件循環並將其設置爲當前事件循環。
由於此函數具有相當複雜的行爲(特別是在使用了自定義事件循環策略的時候),更推薦在協程和回調中使用 get_running_loop() 函數而非 get_event_loop()。
應該考慮使用 asyncio.run() 函數而非使用低層級函數來手動創建和關閉事件循環。
asyncio.set_event_loop(loop):將 loop 設置爲當前 OS 線程的當前事件循環。
asyncio.new_event_loop():創建一個新的事件循環。

使用事件循環創建並運行task任務

import asyncio, time

async def set_after(delay, value):
    await asyncio.sleep(delay)
    print(value)

async def main():
    loop = asyncio.get_running_loop() # 返回當前 系統 線程中正在運行的事件循環。在這裏使用它是用爲 asyncio.run(main()) 已經啓動了事件循環,因此get_running_loop() 可以獲得
    # 在事件循環中創建任務
    task1 = loop.create_task(set_after(2, '... Hello'))
    task2 = loop.create_task(set_after(3, '... world'))
    # 執行任務
    await task1
    await task2

if __name__ == '__main__':
    start_time = time.time()
    # 方式一 直接使用高層函數run() 方法,簡單粗暴,不需要自己管理太多東西
    # asyncio.run(main())
    # 方式二 使用底層的函數 可以更加細緻的控制事件循環
    loop = asyncio.get_event_loop() # 如果這裏替換成get_running_loop() 則會報錯,原因是當前系統中並沒有在運行的事件循環。
    task1 = loop.create_task(set_after(2, '... Hello'))
    task2 = loop.create_task(set_after(3, '... world'))
    loop.run_until_complete(asyncio.wait([task1, task2]))
    print('耗時:', time.time() - start_time)

使用事件循環來使用Future對象

import asyncio, time


async def set_after(fut, delay, value):
    # await asyncio.sleep(delay) # 當使用Future時 沒有await 依然可以運行,但是要set_result,否則會阻塞。使用Future還可以設置返回值,實際中還是看個人應用了。
    fut.set_result(value)
    print(value)

async def say(delay, value):
    await asyncio.sleep(delay)
    print(value)

async def main():
    loop = asyncio.get_running_loop() # 返回當前 系統 線程中正在運行的事件循環。
    # 在事件循環中創建Futrue
    fut1 = loop.create_future()
    fut2 = loop.create_future()
    # 爲Future創建任務
    task1 = loop.create_task(set_after(fut1, 2, '你好'))
    task2 = loop.create_task(set_after(fut2, 3, 'Python'))
    # await task1
    # await task2
    # 可以替換上面語句
    await fut1
    await fut2
    print('得到返回值:', fut1.result(), fut2.result())


if __name__ == '__main__':
    start_time = time.time()
    # 方式一 直接使用高層函數run() 方法,簡單粗暴,不需要自己管理太多東西
    # asyncio.run(main())
    # 方式二 使用底層的函數 可以更加細緻的控制事件循環
    loop = asyncio.get_event_loop() # 如果這裏替換成get_running_loop() 則會報錯,原因是當前系統中並沒有在運行的事件循環。
    future1 = asyncio.ensure_future(say(2, '... Hello'))
    future2 = asyncio.ensure_future(say(3, '... world'))
    # loop.run_until_complete(asyncio.wait([future1, future2]))
    loop.run_until_complete(asyncio.gather(*[future1, future2]))  # 可以替換上面的語句
    print('耗時:', time.time() - start_time)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章