bpo-35621: Support running subprocesses in asyncio when loop is execu… · python/cpython@0d671c0 (original) (raw)
`@@ -117,6 +117,7 @@ asyncio ships with the following built-in policies:
`
117
117
``
118
118
` .. availability:: Windows.
`
119
119
``
``
120
`+
.. _asyncio-watchers:
`
120
121
``
121
122
`Process Watchers
`
122
123
`================
`
`@@ -129,10 +130,11 @@ In asyncio, child processes are created with
`
129
130
`` :func:create_subprocess_exec
and :meth:loop.subprocess_exec
``
130
131
`functions.
`
131
132
``
132
``
`` -
asyncio defines the :class:AbstractChildWatcher
abstract base class,
``
133
``
`-
which child watchers should implement, and has two different
`
134
``
`` -
implementations: :class:SafeChildWatcher
(configured to be used
``
135
``
`` -
by default) and :class:FastChildWatcher
.
``
``
133
`` +
asyncio defines the :class:AbstractChildWatcher
abstract base class, which child
``
``
134
`+
watchers should implement, and has four different implementations:
`
``
135
`` +
:class:ThreadedChildWatcher
(configured to be used by default),
``
``
136
`` +
:class:MultiLoopChildWatcher
, :class:SafeChildWatcher
, and
``
``
137
`` +
:class:FastChildWatcher
.
``
136
138
``
137
139
`` See also the :ref:Subprocess and Threads <asyncio-subprocess-threads>
``
138
140
`section.
`
`@@ -184,23 +186,64 @@ implementation used by the asyncio event loop:
`
184
186
``
185
187
``` Note: loop may be None
.
`186`
`188`
``
``
`189`
`+
.. method:: is_active()
`
``
`190`
`+`
``
`191`
``` +
Return ``True`` if the watcher is ready to use.
``
192
+
``
193
`+
Spawning a subprocess with inactive current child watcher raises
`
``
194
`` +
:exc:RuntimeError
.
``
``
195
+
``
196
`+
.. versionadded:: 3.8
`
``
197
+
187
198
` .. method:: close()
`
188
199
``
189
200
` Close the watcher.
`
190
201
``
191
202
` This method has to be called to ensure that underlying
`
192
203
` resources are cleaned-up.
`
193
204
``
194
``
`-
.. class:: SafeChildWatcher
`
``
205
`+
.. class:: ThreadedChildWatcher
`
``
206
+
``
207
`+
This implementation starts a new waiting thread for every subprocess spawn.
`
``
208
+
``
209
`+
It works reliably even when the asyncio event loop is run in a non-main OS thread.
`
``
210
+
``
211
`+
There is no noticeable overhead when handling a big number of children (O(1) each
`
``
212
`+
time a child terminates), but stating a thread per process requires extra memory.
`
``
213
+
``
214
`+
This watcher is used by default.
`
``
215
+
``
216
`+
.. versionadded:: 3.8
`
195
217
``
196
``
`-
This implementation avoids disrupting other code spawning processes
`
``
218
`+
.. class:: MultiLoopChildWatcher
`
``
219
+
``
220
`` +
This implementation registers a :py:data:SIGCHLD
signal handler on
``
``
221
`+
instantiation. That can break third-party code that installs a custom handler for
`
``
222
`` +
SIGCHLD
. signal).
``
``
223
+
``
224
`+
The watcher avoids disrupting other code spawning processes
`
197
225
`` by polling every process explicitly on a :py:data:SIGCHLD
signal.
``
198
226
``
199
``
`-
This is a safe solution but it has a significant overhead when
`
``
227
`+
There is no limitation for running subprocesses from different threads once the
`
``
228
`+
watcher is installed.
`
``
229
+
``
230
`+
The solution is safe but it has a significant overhead when
`
200
231
` handling a big number of processes (O(n) each time a
`
201
232
`` :py:data:SIGCHLD
is received).
``
202
233
``
203
``
`-
asyncio uses this safe implementation by default.
`
``
234
`+
.. versionadded:: 3.8
`
``
235
+
``
236
`+
.. class:: SafeChildWatcher
`
``
237
+
``
238
`+
This implementation uses active event loop from the main thread to handle
`
``
239
`` +
:py:data:SIGCHLD
signal. If the main thread has no running event loop another
``
``
240
`` +
thread cannot spawn a subprocess (:exc:RuntimeError
is raised).
``
``
241
+
``
242
`+
The watcher avoids disrupting other code spawning processes
`
``
243
`` +
by polling every process explicitly on a :py:data:SIGCHLD
signal.
``
``
244
+
``
245
`` +
This solution is as safe as :class:MultiLoopChildWatcher
and has the same O(N)
``
``
246
`+
complexity but requires a running event loop in the main thread to work.
`
204
247
``
205
248
`.. class:: FastChildWatcher
`
206
249
``
`@@ -211,6 +254,9 @@ implementation used by the asyncio event loop:
`
211
254
` There is no noticeable overhead when handling a big number of
`
212
255
` children (O(1) each time a child terminates).
`
213
256
``
``
257
`+
This solution requires a running event loop in the main thread to work, as
`
``
258
`` +
:class:SafeChildWatcher
.
``
``
259
+
214
260
``
215
261
`Custom Policies
`
216
262
`===============
`