@@ -37,7 +37,6 @@ import uasyncio as asyncio
37
37
  ;  ;  ;  ;  ; 3.2.1 [ Wait on multiple events] ( ./TUTORIAL.md#321-wait-on-multiple-events ) Pause until 1 of N events is set.
38
38
3.3 [ Coordinating multiple tasks] ( ./TUTORIAL.md#33-coordinating-multiple-tasks )
39
39
  ;  ;  ;  ;  ; 3.3.1 [ gather] ( ./TUTORIAL.md#331-gather )
40
-   ;  ;  ;  ;  ; 3.3.2 [ TaskGroups] ( ./TUTORIAL.md#332-taskgroups ) Not yet in official build.
41
40
3.4 [ Semaphore] ( ./TUTORIAL.md#34-semaphore )
42
41
  ;  ;  ;  ;  ; 3.4.1 [ BoundedSemaphore] ( ./TUTORIAL.md#341-boundedsemaphore )
43
42
3.5 [ Queue] ( ./TUTORIAL.md#35-queue )
@@ -134,6 +133,10 @@ mip.install("github:peterhinch/micropython-async/v3/threadsafe")
134
133
```
135
134
For non-networked targets use ` mpremote ` as described in
136
135
[ 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
+ ```
137
140
138
141
###### [ Main README] ( ../README.md )
139
142
@@ -276,7 +279,7 @@ line `main.py` and runs forever.
276
279
277
280
## 2.2 Coroutines and Tasks
278
281
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
280
283
` async def ` and usually contains at least one ` await ` statement. This minimal
281
284
example waits 1 second before printing a message:
282
285
@@ -285,12 +288,16 @@ async def bar():
285
288
await asyncio.sleep(1 )
286
289
print (' Done' )
287
290
```
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:
294
301
295
302
``` python
296
303
import asyncio
@@ -856,79 +863,6 @@ async def main():
856
863
857
864
asyncio.run(main())
858
865
```
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 )
932
866
933
867
## 3.4 Semaphore
934
868
@@ -2061,7 +1995,7 @@ asyncio.run(main())
2061
1995
```
2062
1996
The ` .readline ` method will pause until ` \n ` is received.
2063
1997
2064
- ###### StreamWriter write methods
1998
+ ##### StreamWriter write methods
2065
1999
2066
2000
Writing to a ` StreamWriter ` occurs in two stages. The synchronous ` .write `
2067
2001
method concatenates data for later transmission. The asynchronous ` .drain `
@@ -2078,7 +2012,7 @@ following methods: `ioctl`, `read`, `readline` and `write`. See
2078
2012
[ Writing streaming device drivers] ( ./TUTORIAL.md#64-writing-streaming-device-drivers )
2079
2013
for details on how such drivers may be written in Python.
2080
2014
2081
- ###### StreamReader read methods
2015
+ ##### StreamReader read methods
2082
2016
2083
2017
The ` StreamReader ` read methods fall into two categories depending on whether
2084
2018
they wait for a specific end condition. Thus ` .readline ` pauses until a newline
0 commit comments