策略¶
事件循环策略是一个用于获取和设置当前 事件循环 的全局对象,还可以创建新的事件循环。 默认策略可以可以被 替换 为 内置替代策略 以使用不同的事件循环实现,或者替换为可以覆盖这些行为的 自定义策略。
策略对象 可为每个 context 获取和设置单独的事件循环。 在默认情况下是分线程,不过自定义策略可以按不同的方式定义 context。
自定义事件循环策略可以控制 get_event_loop()
, set_event_loop()
和 new_event_loop()
的行为。
策略对象应该实现 AbstractEventLoopPolicy
抽象基类中定义的API。
获取和设置策略¶
可以使用下面函数获取和设置当前进程的策略:
- asyncio.get_event_loop_policy()¶
返回当前进程域的策略。
- asyncio.set_event_loop_policy(policy)¶
将 policy 设置为当前进程域策略。
如果 policy 设为
None
将恢复默认策略。
策略对象¶
抽象事件循环策略基类定义如下:
- class asyncio.AbstractEventLoopPolicy¶
异步策略的抽象基类。
- get_event_loop()¶
为当前上下文获取事件循环。
返回一个实现
AbstractEventLoop
接口的事件循环对象。该方法永远不应返回
None
。在 3.6 版本发生变更.
- set_event_loop(loop)¶
将当前上下文的事件循环设置为 loop 。
- new_event_loop()¶
创建并返回一个新的事件循环对象。
该方法永远不应返回
None
。
- get_child_watcher()¶
Get a child process watcher object.
Return a watcher object implementing the
AbstractChildWatcher
interface.This function is Unix specific.
自 3.12 版本弃用.
- set_child_watcher(watcher)¶
Set the current child process watcher to watcher.
This function is Unix specific.
自 3.12 版本弃用.
asyncio附带下列内置策略:
- class asyncio.DefaultEventLoopPolicy¶
默认的 asyncio 策略。 在 Unix 上使用
SelectorEventLoop
而在 Windows 上使用ProactorEventLoop
。不需要手动安装默认策略。asyncio已配置成自动使用默认策略。
在 3.8 版本发生变更: 在 Windows 上,现在默认会使用
ProactorEventLoop
。自 3.12 版本弃用: The
get_event_loop()
method of the default asyncio policy now emits aDeprecationWarning
if there is no current event loop set and it decides to create one. In some future Python release this will become an error.
- class asyncio.WindowsSelectorEventLoopPolicy¶
一个使用
SelectorEventLoop
事件循环实现的替代事件循环策略。Availability: Windows.
- class asyncio.WindowsProactorEventLoopPolicy¶
使用
ProactorEventLoop
事件循环实现的另一种事件循环策略。Availability: Windows.
Process Watchers¶
A process watcher allows customization of how an event loop monitors child processes on Unix. Specifically, the event loop needs to know when a child process has exited.
In asyncio, child processes are created with
create_subprocess_exec()
and loop.subprocess_exec()
functions.
asyncio defines the AbstractChildWatcher
abstract base class, which child
watchers should implement, and has four different implementations:
ThreadedChildWatcher
(configured to be used by default),
MultiLoopChildWatcher
, SafeChildWatcher
, and
FastChildWatcher
.
See also the Subprocess and Threads section.
The following two functions can be used to customize the child process watcher implementation used by the asyncio event loop:
- asyncio.get_child_watcher()¶
Return the current child watcher for the current policy.
自 3.12 版本弃用.
- asyncio.set_child_watcher(watcher)¶
Set the current child watcher to watcher for the current policy. watcher must implement methods defined in the
AbstractChildWatcher
base class.自 3.12 版本弃用.
备注
Third-party event loops implementations might not support
custom child watchers. For such event loops, using
set_child_watcher()
might be prohibited or have no effect.
- class asyncio.AbstractChildWatcher¶
- add_child_handler(pid, callback, *args)¶
Register a new child handler.
Arrange for
callback(pid, returncode, *args)
to be called when a process with PID equal to pid terminates. Specifying another callback for the same process replaces the previous handler.The callback callable must be thread-safe.
- remove_child_handler(pid)¶
Removes the handler for process with PID equal to pid.
The function returns
True
if the handler was successfully removed,False
if there was nothing to remove.
- attach_loop(loop)¶
Attach the watcher to an event loop.
If the watcher was previously attached to an event loop, then it is first detached before attaching to the new loop.
Note: loop may be
None
.
- is_active()¶
Return
True
if the watcher is ready to use.Spawning a subprocess with inactive current child watcher raises
RuntimeError
.Added in version 3.8.
- close()¶
Close the watcher.
This method has to be called to ensure that underlying resources are cleaned-up.
自 3.12 版本弃用.
- class asyncio.ThreadedChildWatcher¶
This implementation starts a new waiting thread for every subprocess spawn.
It works reliably even when the asyncio event loop is run in a non-main OS thread.
There is no noticeable overhead when handling a big number of children (O(1) each time a child terminates), but starting a thread per process requires extra memory.
This watcher is used by default.
Added in version 3.8.
- class asyncio.MultiLoopChildWatcher¶
This implementation registers a
SIGCHLD
signal handler on instantiation. That can break third-party code that installs a custom handler forSIGCHLD
signal.The watcher avoids disrupting other code spawning processes by polling every process explicitly on a
SIGCHLD
signal.There is no limitation for running subprocesses from different threads once the watcher is installed.
The solution is safe but it has a significant overhead when handling a big number of processes (O(n) each time a
SIGCHLD
is received).Added in version 3.8.
自 3.12 版本弃用.
- class asyncio.SafeChildWatcher¶
This implementation uses active event loop from the main thread to handle
SIGCHLD
signal. If the main thread has no running event loop another thread cannot spawn a subprocess (RuntimeError
is raised).The watcher avoids disrupting other code spawning processes by polling every process explicitly on a
SIGCHLD
signal.This solution is as safe as
MultiLoopChildWatcher
and has the same O(n) complexity but requires a running event loop in the main thread to work.自 3.12 版本弃用.
- class asyncio.FastChildWatcher¶
This implementation reaps every terminated processes by calling
os.waitpid(-1)
directly, possibly breaking other code spawning processes and waiting for their termination.There is no noticeable overhead when handling a big number of children (O(1) each time a child terminates).
This solution requires a running event loop in the main thread to work, as
SafeChildWatcher
.自 3.12 版本弃用.
- class asyncio.PidfdChildWatcher¶
This implementation polls process file descriptors (pidfds) to await child process termination. In some respects,
PidfdChildWatcher
is a "Goldilocks" child watcher implementation. It doesn't require signals or threads, doesn't interfere with any processes launched outside the event loop, and scales linearly with the number of subprocesses launched by the event loop. The main disadvantage is that pidfds are specific to Linux, and only work on recent (5.3+) kernels.Added in version 3.9.
自定义策略¶
要实现一个新的事件循环策略,建议子类化 DefaultEventLoopPolicy
并重写需要定制行为的方法,例如:
class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
def get_event_loop(self):
"""获取事件循环。
这可能为 None 或是一个 EventLoop 的实例。
"""
loop = super().get_event_loop()
# 对 loop 执行一些操作 ...
return loop
asyncio.set_event_loop_policy(MyEventLoopPolicy())