什麼是事件循環:
事件循環是每個 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)