Runners (執行器)¶
這個章節概述用於執行 asyncio 程式碼的高階 asyncio 原始物件。
他們是基於一個事件迴圈,目的是為了簡化常見且廣泛運用場景的非同步程式碼。
運行一個 asyncio 程式¶
- asyncio.run(coro, *, debug=None, loop_factory=None)¶
執行協程 (coroutine) coro 並回傳結果。
這個函式負責運行被傳入的協程、管理 asyncio 的事件迴圈、終結非同步產生器,以及關閉執行器。
當另一個非同步事件迴圈在同一執行緒中執行時,無法呼叫此函式。
如果 debug 為
True
,事件迴圈會以除錯模式執行。False
則會關閉除錯模式。None
則會優先使用除錯模式的全域設定。如果 loop_factory 不為
None
,它會被用於建立一個新的事件迴圈;否則會改用asyncio.new_event_loop()
。迴圈會在最後關閉。這個函式應該要作為asyncio 程式的主要進入點,且理想上僅會被呼叫一次。推薦使用 loop_factory 來設定事件迴圈時而不是使用 policies(政策)。The executor is given a timeout duration of 5 minutes to shutdown. If the executor hasn't finished within that duration, a warning is emitted and the executor is closed.
範例:
async def main(): await asyncio.sleep(1) print('hello') asyncio.run(main())
在 3.7 版被加入.
在 3.9 版的變更: Updated to use
loop.shutdown_default_executor()
.在 3.10 版的變更: debug is
None
by default to respect the global debug mode settings.在 3.12 版的變更: 新增 loop_factory 參數。
Runner context manager¶
- class asyncio.Runner(*, debug=None, loop_factory=None)¶
A context manager that simplifies multiple async function calls in the same context.
Sometimes several top-level async functions should be called in the same event loop and
contextvars.Context
.如果 debug 為
True
,事件迴圈會以除錯模式執行。False
則會關閉除錯模式。None
則會優先使用除錯模式的全域設定。loop_factory could be used for overriding the loop creation. It is the responsibility of the loop_factory to set the created loop as the current one. By default
asyncio.new_event_loop()
is used and set as current event loop withasyncio.set_event_loop()
if loop_factory isNone
.Basically,
asyncio.run()
example can be rewritten with the runner usage:async def main(): await asyncio.sleep(1) print('hello') with asyncio.Runner() as runner: runner.run(main())
在 3.11 版被加入.
- run(coro, *, context=None)¶
Run a coroutine coro in the embedded loop.
Return the coroutine's result or raise its exception.
An optional keyword-only context argument allows specifying a custom
contextvars.Context
for the coro to run in. The runner's default context is used ifNone
.當另一個非同步事件迴圈在同一執行緒中執行時,無法呼叫此函式。
- close()¶
Close the runner.
Finalize asynchronous generators, shutdown default executor, close the event loop and release embedded
contextvars.Context
.
- get_loop()¶
Return the event loop associated with the runner instance.
備註
Runner
uses the lazy initialization strategy, its constructor doesn't initialize underlying low-level structures.Embedded loop and context are created at the
with
body entering or the first call ofrun()
orget_loop()
.
Handling Keyboard Interruption¶
在 3.11 版被加入.
When signal.SIGINT
is raised by Ctrl-C, KeyboardInterrupt
exception is raised in the main thread by default. However this doesn't work with
asyncio
because it can interrupt asyncio internals and can hang the program from
exiting.
To mitigate this issue, asyncio
handles signal.SIGINT
as follows:
asyncio.Runner.run()
installs a customsignal.SIGINT
handler before any user code is executed and removes it when exiting from the function.The
Runner
creates the main task for the passed coroutine for its execution.When
signal.SIGINT
is raised by Ctrl-C, the custom signal handler cancels the main task by callingasyncio.Task.cancel()
which raisesasyncio.CancelledError
inside the main task. This causes the Python stack to unwind,try/except
andtry/finally
blocks can be used for resource cleanup. After the main task is cancelled,asyncio.Runner.run()
raisesKeyboardInterrupt
.A user could write a tight loop which cannot be interrupted by
asyncio.Task.cancel()
, in which case the second following Ctrl-C immediately raises theKeyboardInterrupt
without cancelling the main task.