Skip to content

Commit 99421dc

Browse files
committed
TUTORIAL: Remove task groups. A wish unfulfilled...
1 parent ccc21a0 commit 99421dc

File tree

1 file changed

+17
-83
lines changed

1 file changed

+17
-83
lines changed

v3/docs/TUTORIAL.md

Lines changed: 17 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import uasyncio as asyncio
3737
     3.2.1 [Wait on multiple events](./TUTORIAL.md#321-wait-on-multiple-events) Pause until 1 of N events is set.
3838
3.3 [Coordinating multiple tasks](./TUTORIAL.md#33-coordinating-multiple-tasks)
3939
     3.3.1 [gather](./TUTORIAL.md#331-gather)
40-
     3.3.2 [TaskGroups](./TUTORIAL.md#332-taskgroups) Not yet in official build.
4140
3.4 [Semaphore](./TUTORIAL.md#34-semaphore)
4241
     3.4.1 [BoundedSemaphore](./TUTORIAL.md#341-boundedsemaphore)
4342
3.5 [Queue](./TUTORIAL.md#35-queue)
@@ -134,6 +133,10 @@ mip.install("github:peterhinch/micropython-async/v3/threadsafe")
134133
```
135134
For non-networked targets use `mpremote` as described in
136135
[the official docs](http://docs.micropython.org/en/latest/reference/packages.html#installing-packages-with-mpremote).
136+
```bash
137+
$ mpremote mip install github:peterhinch/micropython-async/v3/primitives
138+
$ mpremote mip install github:peterhinch/micropython-async/v3/threadsafe
139+
```
137140

138141
###### [Main README](../README.md)
139142

@@ -276,7 +279,7 @@ line `main.py` and runs forever.
276279

277280
## 2.2 Coroutines and Tasks
278281

279-
The fundmental building block of `asyncio` is a coro. This is defined with
282+
The fundamental building block of `asyncio` is a coro. This is defined with
280283
`async def` and usually contains at least one `await` statement. This minimal
281284
example waits 1 second before printing a message:
282285

@@ -285,12 +288,16 @@ async def bar():
285288
await asyncio.sleep(1)
286289
print('Done')
287290
```
288-
289-
V3 `asyncio` introduced the concept of a `Task`. A `Task` instance is created
290-
from a coro by means of the `create_task` method, which causes the coro to be
291-
scheduled for execution and returns a `Task` instance. In many cases, coros and
292-
tasks are interchangeable: the official docs refer to them as `awaitable`, for
293-
the reason that either of them may be the target of an `await`. Consider this:
291+
Just as a function does nothing until called, a coro does nothing until awaited
292+
or converted to a `Task`. The `create_task` method takes a coro as its argument
293+
and returns a `Task` instance, which is scheduled for execution. In
294+
```python
295+
async def foo():
296+
await coro
297+
```
298+
`coro` is run with `await` pausing until `coro` has completed. Sometimes coros
299+
and tasks are interchangeable: the CPython docs refer to them as `awaitable`,
300+
because either may be the target of an `await`. Consider this:
294301

295302
```python
296303
import asyncio
@@ -856,79 +863,6 @@ async def main():
856863

857864
asyncio.run(main())
858865
```
859-
### 3.3.2 TaskGroups
860-
861-
The `TaskGroup` class is unofficially provided by
862-
[this PR](https://github.com/micropython/micropython/pull/8791). It is well
863-
suited to applications where one or more of a group of tasks is subject to
864-
runtime exceptions. A `TaskGroup` is instantiated in an asynchronous context
865-
manager. The `TaskGroup` instantiates member tasks. When all have run to
866-
completion, the context manager terminates. Where `gather` is static, a task
867-
group can be dynamic: a task in a group may spawn further group members. Return
868-
values from member tasks cannot be retrieved. Results should be passed in other
869-
ways such as via bound variables, queues etc.
870-
871-
An exception in a member task not trapped by that task is propagated to the
872-
task that created the `TaskGroup`. All tasks in the `TaskGroup` then terminate
873-
in an orderly fashion: cleanup code in any `finally` clause will run. When all
874-
cleanup code has completed, the context manager completes, and execution passes
875-
to an exception handler in an outer scope.
876-
877-
If a member task is cancelled in code, that task terminates in an orderly way
878-
but the other members continue to run.
879-
880-
The following illustrates the basic salient points of using a `TaskGroup`:
881-
```python
882-
import asyncio
883-
async def foo(n):
884-
for x in range(10 + n):
885-
print(f"Task {n} running.")
886-
await asyncio.sleep(1 + n/10)
887-
print(f"Task {n} done")
888-
889-
async def main():
890-
async with asyncio.TaskGroup() as tg: # Context manager pauses until members terminate
891-
for n in range(4):
892-
tg.create_task(foo(n)) # tg.create_task() creates a member task
893-
print("TaskGroup done") # All tasks have terminated
894-
895-
asyncio.run(main())
896-
```
897-
This more complete example illustrates an exception which is not trapped by the
898-
member task. Cleanup code on all members runs when the exception occurs,
899-
followed by exception handling code in `main()`.
900-
```python
901-
import asyncio
902-
fail = True # Set False to demo normal completion
903-
async def foo(n):
904-
print(f"Task {n} running...")
905-
try:
906-
for x in range(10 + n):
907-
await asyncio.sleep(1 + n/10)
908-
if n==0 and x==5 and fail:
909-
raise OSError("Uncaught exception in task.")
910-
print(f"Task {n} done")
911-
finally:
912-
print(f"Task {n} cleanup")
913-
914-
async def main():
915-
try:
916-
async with asyncio.TaskGroup() as tg:
917-
for n in range(4):
918-
tg.create_task(foo(n))
919-
print("TaskGroup done") # Does not get here if a task throws exception
920-
except Exception as e:
921-
print(f'TaskGroup caught exception: "{e}"')
922-
finally:
923-
print("TaskGroup finally")
924-
925-
asyncio.run(main())
926-
```
927-
[This doc](https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/)
928-
provides background on the theory behind task groups and how they can improve
929-
program structure and reliablity.
930-
931-
###### [Contents](./TUTORIAL.md#contents)
932866

933867
## 3.4 Semaphore
934868

@@ -2061,7 +1995,7 @@ asyncio.run(main())
20611995
```
20621996
The `.readline` method will pause until `\n` is received.
20631997

2064-
###### StreamWriter write methods
1998+
##### StreamWriter write methods
20651999

20662000
Writing to a `StreamWriter` occurs in two stages. The synchronous `.write`
20672001
method concatenates data for later transmission. The asynchronous `.drain`
@@ -2078,7 +2012,7 @@ following methods: `ioctl`, `read`, `readline` and `write`. See
20782012
[Writing streaming device drivers](./TUTORIAL.md#64-writing-streaming-device-drivers)
20792013
for details on how such drivers may be written in Python.
20802014

2081-
###### StreamReader read methods
2015+
##### StreamReader read methods
20822016

20832017
The `StreamReader` read methods fall into two categories depending on whether
20842018
they wait for a specific end condition. Thus `.readline` pauses until a newline

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