執行器¶
本節概述了用於執行 asyncio 程式碼的高階 asyncio 原語。
它們構建在 事件迴圈 之上,旨在簡化常見廣泛場景的非同步程式碼使用。
執行 asyncio 程式¶
- asyncio.run(coro, *, debug=None, loop_factory=None)¶
執行 協程 *coro* 並返回結果。
此函式執行傳遞的協程,負責管理 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* 引數。
執行器上下文管理器¶
- 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*。
返回協程的結果或引發其異常。
可選的僅關鍵字 *context* 引數允許為要執行的 *coro* 指定自定義
contextvars.Context
。如果None
,則使用執行器的預設上下文。當同一執行緒中執行另一個 asyncio 事件迴圈時,無法呼叫此函式。
- close()¶
關閉執行器。
最終化非同步生成器、關閉預設執行器、關閉事件迴圈並釋放嵌入式
contextvars.Context
。
- get_loop()¶
返回與執行器例項關聯的事件迴圈。
注意
Runner
使用延遲初始化策略,其建構函式不初始化底層低階結構。嵌入式 *loop* 和 *context* 在進入
with
主體或首次呼叫run()
或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
,而不會取消主任務。