Skip to content

Commit ce9ea8f

Browse files
committed
docs/library/asyncio: Add a section on taskgroups.
Signed-off-by: Matthias Urlichs <matthias@urlichs.de>
1 parent 12defaf commit ce9ea8f

File tree

2 files changed

+99
-4
lines changed

2 files changed

+99
-4
lines changed

docs/library/asyncio.rst

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,76 @@ class Task
112112
ignore this exception. Cleanup code may be run by trapping it, or via
113113
``try ... finally``.
114114

115+
class Taskgroup
116+
---------------
117+
118+
See Nathaniel J. Smith's `essay on Structured Concurrency
119+
<https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/>`_
120+
for an introduction why you should use taskgroups instead of starting
121+
"naked" tasks.
122+
123+
.. note::
124+
His "nursery" objects are called "taskgroup" in asyncio; the
125+
equivalent of a "go statement" is `Loop.create_task`.
126+
127+
.. class:: Taskgroup()
128+
129+
This object is an async context managed holding a group of tasks.
130+
Tasks can be added to the group using `Taskgroup.create_task`.
131+
132+
If a task belonging to the group fails, the remaining tasks in the
133+
group are cancelled with an :exc:`asyncio.CancelledError` exception.
134+
(This also holds for the code within the context manager's block.)
135+
No further tasks can then be added to the group.
136+
137+
When there is no exception, leaving the context manager waits for
138+
the taskgroup's member tasks to end before proceeding. It does not
139+
cancel these tasks and does not prevent the creation of new tasks.
140+
141+
.. method:: Taskgroup.create_task(coroutine)
142+
143+
Create a subtask that executes *coroutine* as part of this taskgroup.
144+
145+
Returns the new task.
146+
147+
.. method:: Taskgroup.cancel()
148+
149+
Stop the taskgroup, i.e. cancel all its tasks.
150+
151+
This method is equivalent to cancelling the task responsible for the
152+
body of the taskgroup, *if* that is what the task is currently doing.
153+
154+
.. exception:: Cancelled
155+
156+
This exception is raised in a task whose taskgroup is being cancelled.
157+
158+
This is a subclass of ``BaseException``; it should never be caught.
159+
160+
.. exception:: ExceptionGroup
161+
162+
If multiple subtasks raise exceptions in parallel, it's unclear which
163+
of them should be propagated. Thus an `ExceptionGroup` exception
164+
collects them and is raised instead.
165+
166+
.. method:: ExceptionGroup.split(typ)
167+
168+
This method can be used to filter the exceptions within an exception group.
169+
It returns two lists: the first contains those sub-exceptions which
170+
match *typ*, the second those which do not.
171+
172+
*typ* can be an exception class, a list of exception classes, or a
173+
callable that returns ``True`` if the exception passed to it should be
174+
returned in the first list.
175+
176+
MicroPython does not support CPython 3.11's syntax for filtering handling
177+
exception groups.
178+
179+
.. exception:: BaseExceptionGroup
180+
181+
Like `ExceptionGroup`, but used if one of the sub-exceptions is not a
182+
subclass of `Exception`.
183+
184+
115185
class Event
116186
-----------
117187

@@ -214,20 +284,37 @@ TCP stream connections
214284

215285
.. function:: start_server(callback, host, port, backlog=5)
216286

217-
Start a TCP server on the given *host* and *port*. The *callback* will be
218-
called with incoming, accepted connections, and be passed 2 arguments: reader
219-
and writer streams for the connection.
287+
Start a TCP server on the given *host* and *port*. For each incoming,
288+
accepted connection, *callback* will be called in a new task with
289+
2 arguments: reader and writer streams for the connection.
290+
291+
If you use taskgroups, you should use `run_server` instead.
220292

221293
Returns a `Server` object.
222294

223295
This is a coroutine.
224296

297+
.. function:: run_server(callback, host, port, backlog=5, taskgroup=None)
298+
299+
Start a TCP server on the given *host* and *port*. For each incoming,
300+
accepted connection, *callback* will be called in a new task with
301+
2 arguments: reader and writer streams for the connection.
302+
303+
The new task is started in *taskgroup*. An internal taskgroup will be
304+
used if none is passed in.
305+
306+
This is a coroutine. It does not return unless cancelled.
307+
308+
225309
.. class:: Stream()
226310

227311
This represents a TCP stream connection. To minimise code this class implements
228312
both a reader and a writer, and both ``StreamReader`` and ``StreamWriter`` alias to
229313
this class.
230314

315+
This class should be used as an async context manager. Leaving the context
316+
will close the connection.
317+
231318
.. method:: Stream.get_extra_info(v)
232319

233320
Get extra information about the stream, given by *v*. The valid values for *v* are:
@@ -237,6 +324,12 @@ TCP stream connections
237324

238325
Close the stream.
239326

327+
Depending on the stream's concrete implementation, this call may do
328+
nothing. You should call the `wait_closed` coroutine immediately
329+
afterwards.
330+
331+
Streams are closed implicitly when used as an async context manager.
332+
240333
.. method:: Stream.wait_closed()
241334

242335
Wait for the stream to close.
@@ -323,6 +416,8 @@ Event Loop
323416

324417
Create a task from the given *coro* and return the new `Task` object.
325418

419+
You should not call this function when you're using taskgroups.
420+
326421
.. method:: Loop.run_forever()
327422

328423
Run the event loop until `stop()` is called.

extmod/asyncio/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def run_until_complete(main_task=None):
242242
_exc_context["exception"] = exc
243243
_exc_context["future"] = t
244244
Loop.call_exception_handler(_exc_context)
245-
# XXX if we do await it later,
245+
# XXX if we do await the task later,
246246
# leaving t.data as None will cause a fault.
247247
t.data = exc
248248

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy