Runners¶
Source code:Lib/asyncio/runners.py
This section outlines high-level asyncio primitives to run asyncio code.
They are built on top of anevent loop with the aimto simplify async code usage for common wide-spread scenarios.
Running an asyncio Program¶
- asyncio.run(coro,*,debug=None)¶
Execute thecoroutinecoro and return the result.
This function runs the passed coroutine, taking care ofmanaging the asyncio event loop,finalizing asynchronousgenerators, and closing the threadpool.
This function cannot be called when another asyncio event loop isrunning in the same thread.
Ifdebug is
True, the event loop will be run in debug mode.Falsedisablesdebug mode explicitly.Noneis used to respect the globalDebug Mode settings.This function always creates a new event loop and closes it atthe end. It should be used as a main entry point for asyncioprograms, and should ideally only be called once.
Example:
asyncdefmain():awaitasyncio.sleep(1)print('hello')asyncio.run(main())
New in version 3.7.
Changed in version 3.9:Updated to use
loop.shutdown_default_executor().Changed in version 3.10:debug is
Noneby default to respect the global debug mode settings.
Runner context manager¶
- classasyncio.Runner(*,debug=None,loop_factory=None)¶
A context manager that simplifiesmultiple async function calls in the samecontext.
Sometimes several top-level async functions should be called in the sameeventloop and
contextvars.Context.Ifdebug is
True, the event loop will be run in debug mode.Falsedisablesdebug mode explicitly.Noneis used to respect the globalDebug Mode settings.loop_factory could be used for overriding the loop creation.It is the responsibility of theloop_factory to set the created loop as thecurrent one. By default
asyncio.new_event_loop()is used and set ascurrent event loop withasyncio.set_event_loop()ifloop_factory isNone.Basically,
asyncio.run()example can be rewritten with the runner usage:asyncdefmain():awaitasyncio.sleep(1)print('hello')withasyncio.Runner()asrunner:runner.run(main())
New in version 3.11.
- run(coro,*,context=None)¶
Run acoroutinecoro in the embedded loop.
Return the coroutine’s result or raise its exception.
An optional keyword-onlycontext argument allows specifying acustom
contextvars.Contextfor thecoro to run in.The runner’s default context is used ifNone.This function cannot be called when another asyncio event loop isrunning in the same thread.
- close()¶
Close the runner.
Finalize asynchronous generators, shutdown default executor, close the event loopand release embedded
contextvars.Context.
- get_loop()¶
Return the event loop associated with the runner instance.
Note
Runneruses the lazy initialization strategy, its constructor doesn’tinitialize underlying low-level structures.Embeddedloop andcontext are created at the
withbody enteringor the first call ofrun()orget_loop().
Handling Keyboard Interruption¶
New in version 3.11.
Whensignal.SIGINT is raised byCtrl-C,KeyboardInterruptexception is raised in the main thread by default. However this doesn’t work withasyncio because it can interrupt asyncio internals and can hang the program fromexiting.
To mitigate this issue,asyncio handlessignal.SIGINT as follows:
asyncio.Runner.run()installs a customsignal.SIGINThandler beforeany user code is executed and removes it when exiting from the function.The
Runnercreates the main task for the passed coroutine for itsexecution.When
signal.SIGINTis raised byCtrl-C, the custom signal handlercancels the main task by callingasyncio.Task.cancel()which raisesasyncio.CancelledErrorinside the main task. This causes the Python stackto unwind,try/exceptandtry/finallyblocks can be used for resourcecleanup. 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 followingCtrl-Cimmediately raises theKeyboardInterruptwithout cancelling the main task.