執行器¶
本節概述了用於執行 asyncio 程式碼的高階 asyncio 原語。
它們建立在事件迴圈之上,旨在簡化常見廣泛場景下的非同步程式碼使用。
執行 asyncio 程式¶
- asyncio.run(coro, *, debug=None, loop_factory=None)¶
在 asyncio 事件迴圈中執行 coro 並返回結果。
該引數可以是任何 awaitable 物件。
此函式執行 awaitable,負責管理 asyncio 事件迴圈,完成非同步生成器,並關閉執行器。
當同一執行緒中執行另一個 asyncio 事件迴圈時,不能呼叫此函式。
如果 debug 為
True
,事件迴圈將以除錯模式執行。False
明確停用除錯模式。None
用於遵循全域性的除錯模式設定。如果 loop_factory 不是
None
,它將用於建立新的事件迴圈;否則使用asyncio.new_event_loop()
。迴圈在結束時關閉。此函式應作為 asyncio 程式的主要入口點使用,理想情況下應只調用一次。建議使用 loop_factory 來配置事件迴圈,而不是策略。傳遞asyncio.EventLoop
允許在沒有策略系統的情況下執行 asyncio。執行器被賦予 5 分鐘的超時時間來關閉。如果執行器未在該時間內完成,則會發出警告並關閉執行器。
示例
async def main(): await asyncio.sleep(1) print('hello') asyncio.run(main())
在 3.7 版本加入。
3.9 版本中變更: 更新為使用
loop.shutdown_default_executor()
。3.10 版本中變更: debug 預設為
None
,以遵循全域性除錯模式設定。3.12 版本中變更: 添加了 loop_factory 引數。
3.14 版本中變更: coro 可以是任何 awaitable 物件。
備註
asyncio
策略系統已棄用,並將在 Python 3.16 中移除;從那時起,將需要顯式的 loop_factory 來配置事件迴圈。
執行器上下文管理器¶
- class asyncio.Runner(*, debug=None, loop_factory=None)¶
一個上下文管理器,它簡化了同一上下文中的多個非同步函式呼叫。
有時,幾個頂級非同步函式應在同一個事件迴圈和
contextvars.Context
中呼叫。如果 debug 為
True
,事件迴圈將以除錯模式執行。False
明確停用除錯模式。None
用於遵循全域性的除錯模式設定。loop_factory 可用於覆蓋迴圈建立。由 loop_factory 負責將建立的迴圈設定為當前迴圈。預設情況下,如果 loop_factory 為
None
,則使用asyncio.new_event_loop()
並使用asyncio.set_event_loop()
將其設定為當前事件迴圈。基本上,
asyncio.run()
示例可以透過使用執行器來重寫async def main(): await asyncio.sleep(1) print('hello') with asyncio.Runner() as runner: runner.run(main())
在 3.11 版本中新增。
- run(coro, *, context=None)¶
在嵌入的事件迴圈中執行 coro。
該引數可以是任何 awaitable 物件。
如果引數是協程,它將被封裝在一個任務中。
一個可選的僅關鍵字 context 引數允許為要執行的程式碼指定自定義的
contextvars.Context
。如果 context 為None
,則使用執行器的預設上下文。返回 awaitable 的結果或引發異常。
當同一執行緒中執行另一個 asyncio 事件迴圈時,不能呼叫此函式。
3.14 版本中變更: coro 可以是任何 awaitable 物件。
- close()¶
關閉執行器。
完成非同步生成器,關閉預設執行器,關閉事件迴圈並釋放嵌入的
contextvars.Context
。
- get_loop()¶
返回與執行器例項關聯的事件迴圈。
處理鍵盤中斷¶
在 3.11 版本中新增。
當透過 Ctrl-C 觸發 signal.SIGINT
時,預設情況下主執行緒會引發 KeyboardInterrupt
異常。然而,這不適用於 asyncio
,因為它可能中斷 asyncio 內部機制並導致程式無法退出。
為了解決這個問題,asyncio
按如下方式處理 signal.SIGINT
asyncio.Runner.run()
在任何使用者程式碼執行之前安裝自定義的signal.SIGINT
處理器,並在函式退出時將其移除。為了執行傳入的協程,
Runner
會為其建立一個主任務。當透過 Ctrl-C 引發
signal.SIGINT
時,自定義訊號處理器會透過呼叫asyncio.Task.cancel()
來取消主任務,這會在主任務內部引發asyncio.CancelledError
。這會導致 Python 棧展開,try/except
和try/finally
塊可用於資源清理。主任務取消後,asyncio.Runner.run()
會引發KeyboardInterrupt
。使用者可能會編寫一個無法被
asyncio.Task.cancel()
中斷的緊密迴圈,在這種情況下,第二次連續的 Ctrl-C 將立即引發KeyboardInterrupt
,而不會取消主任務。