Skip to content

Commit 3941ce5

Browse files
committed
Tutorial improvements.
1 parent f69b615 commit 3941ce5

File tree

2 files changed

+36
-33
lines changed

2 files changed

+36
-33
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ course.
4646

4747
The documentation and code in this repository are based on `uasyncio` version
4848
2.0, which is the version on PyPi and in the official micropython-lib. This
49-
requires firmware dated 22nd Feb 2018 or later. Use of the IORead mechanism
49+
requires firmware dated 22nd Feb 2018 or later. Use of the stream I/O mechanism
5050
requires firmware after 17th June 2018.
5151

5252
See [tutorial](./TUTORIAL.md#installing-uasyncio-on-bare-metal) for

TUTORIAL.md

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,11 @@ and rebuilding.
125125

126126
5.2 [Polling hardware with a coroutine](./TUTORIAL.md#52-polling-hardware-with-a-coroutine)
127127

128-
5.3 [Using the IORead mechnanism](./TUTORIAL.md#53-using-the-ioread-mechanism)
128+
5.3 [Using the stream mechnanism](./TUTORIAL.md#53-using-the-stream-mechanism)
129129

130130
5.3.1 [A UART driver example](./TUTORIAL.md#531-a-uart-driver-example)
131131

132-
5.4 [Writing IORead device drivers](./TUTORIAL.md#54-writing-ioread-device-drivers)
132+
5.4 [Writing streaming device drivers](./TUTORIAL.md#54-writing-streaming-device-drivers)
133133

134134
5.5 [A complete example: aremote.py](./TUTORIAL.md#55-a-complete-example-aremotepy)
135135
A driver for an IR remote control receiver.
@@ -186,8 +186,8 @@ The following modules are provided which may be copied to the target hardware.
186186
**Libraries**
187187

188188
1. `asyn.py` Provides synchronisation primitives `Lock`, `Event`, `Barrier`,
189-
`Semaphore` and `BoundedSemaphore`. Provides support for task cancellation via
190-
`NamedTask` and `Cancellable` classes.
189+
`Semaphore`, `BoundedSemaphore`, `Condition` and `gather`. Provides support
190+
for task cancellation via `NamedTask` and `Cancellable` classes.
191191
2. `aswitch.py` This provides classes for interfacing switches and
192192
pushbuttons and also a software retriggerable delay object. Pushbuttons are a
193193
generalisation of switches providing logical rather than physical status along
@@ -215,7 +215,7 @@ results by accessing Pyboard hardware.
215215
11. `auart_hd.py` Use of the Pyboard UART to communicate with a device using a
216216
half-duplex protocol. Suits devices such as those using the 'AT' modem command
217217
set.
218-
12. `iorw.py` Demo of a read/write device driver using the IORead mechanism.
218+
12. `iorw.py` Demo of a read/write device driver using the stream I/O mechanism.
219219

220220
**Test Programs**
221221

@@ -247,14 +247,14 @@ Consider the following example:
247247

248248
```python
249249
import uasyncio as asyncio
250-
loop = asyncio.get_event_loop()
251250
async def bar():
252251
count = 0
253252
while True:
254253
count += 1
255254
print(count)
256255
await asyncio.sleep(1) # Pause 1s
257256

257+
loop = asyncio.get_event_loop()
258258
loop.create_task(bar()) # Schedule ASAP
259259
loop.run_forever()
260260
```
@@ -272,11 +272,12 @@ loop's `run_until_complete` method. Examples of this may be found in the
272272
`astests.py` module.
273273

274274
The event loop instance is a singleton, instantiated by a program's first call
275-
to `asyncio.get_event_loop()`. This takes an optional integer arg being the
276-
length of the coro queue - i.e. the maximum number of concurrent coros allowed.
277-
The default of 42 is likely to be adequate for most purposes. If a coro needs
278-
to call an event loop method, calling `asyncio.get_event_loop()` (without
279-
args) will efficiently return it.
275+
to `asyncio.get_event_loop()`. This takes two optional integer args being the
276+
lengths of the two coro queues - i.e. the maximum number of concurrent coros
277+
allowed. The default of 16 is likely to be adequate for most purposes.
278+
279+
If a coro needs to call an event loop method (usually `create_task`), calling
280+
`asyncio.get_event_loop()` (without args) will efficiently return it.
280281

281282
###### [Contents](./TUTORIAL.md#contents)
282283

@@ -317,7 +318,8 @@ the `roundrobin.py` example.
317318
any required arguments passed. The `run_until_complete` call returns when
318319
the coro terminates: this method provides a way of quitting the scheduler.
319320
* `await` Arg: the coro to run, specified with function call syntax. Starts
320-
the coro ASAP and blocks until it has run to completion.
321+
the coro ASAP. The awaiting coro blocks until the awaited one has run to
322+
completion.
321323

322324
The above are compatible with CPython. Additional uasyncio methods are
323325
discussed in 2.2.3 below.
@@ -395,14 +397,15 @@ compete to access a single resource. An example is provided in the `astests.py`
395397
program and discussed in [the docs](./DRIVERS.md). Another hazard is the "deadly
396398
embrace" where two coros each wait on the other's completion.
397399

398-
In simple applications communication may be achieved with global flags. A more
399-
elegant approach is to use synchronisation primitives. The module
400+
In simple applications communication may be achieved with global flags or bound
401+
variables. A more elegant approach is to use synchronisation primitives. The
402+
module
400403
[asyn.py](https://github.com/peterhinch/micropython-async/blob/master/asyn.py)
401404
offers "micro" implementations of `Event`, `Barrier`, `Semaphore` and
402405
`Condition` primitives. These are for use only with asyncio. They are not
403406
thread safe and should not be used with the `_thread` module or from an
404407
interrupt handler except where mentioned. A `Lock` primitive is provided which
405-
is partially superseded by an official implementation.
408+
is an alterantive to the official implementation.
406409

407410
Another synchronisation issue arises with producer and consumer coros. The
408411
producer generates data which the consumer uses. Asyncio provides the `Queue`
@@ -460,9 +463,9 @@ ineffective. It will not receive the `TimeoutError` until it has acquired the
460463
lock. The same observation applies to task cancellation.
461464

462465
The module `asyn.py` offers a `Lock` class which works in these situations
463-
[full details](./PRIMITIVES.md#32-class-lock). It is significantly less
464-
efficient than the official class but supports additional interfaces as per the
465-
CPython version including context manager usage.
466+
[see docs](./PRIMITIVES.md#32-class-lock). It is significantly less efficient
467+
than the official class but supports additional interfaces as per the CPython
468+
version including context manager usage.
466469

467470
###### [Contents](./TUTORIAL.md#contents)
468471

@@ -691,9 +694,9 @@ async def foo():
691694
print('Done')
692695
```
693696

694-
**Note** It is bad practice to issue the close() method to a de-scheduled
695-
coro. This subverts the scheduler by causing the coro to execute code even
696-
though descheduled. This is likely to have unwanted consequences.
697+
**Note** It is bad practice to issue the `close` or `throw` methods of a
698+
de-scheduled coro. This subverts the scheduler by causing the coro to execute
699+
code even though descheduled. This is likely to have unwanted consequences.
697700

698701
###### [Contents](./TUTORIAL.md#contents)
699702

@@ -1015,7 +1018,7 @@ while a coroutine awaiting the outcome polls the object each time it is
10151018
scheduled.
10161019

10171020
Polling may be effected in two ways, explicitly or implicitly. The latter is
1018-
performed by using the `IORead` mechanism which is a system designed for stream
1021+
performed by using the `stream I/O` mechanism which is a system designed for stream
10191022
devices such as UARTs and sockets. At its simplest explicit polling may consist
10201023
of code like this:
10211024

@@ -1034,10 +1037,10 @@ an awaitable class might be used. Explicit polling is discussed
10341037
further [below](./TUTORIAL.md#52-polling-hardware-with-a-coroutine).
10351038

10361039
Implicit polling consists of designing the driver to behave like a stream I/O
1037-
device such as a socket or UART, using `IORead`. This polls devices using
1040+
device such as a socket or UART, using `stream I/O`. This polls devices using
10381041
Python's `select.poll` system: because the polling is done in C it is faster
1039-
and more efficient than explicit polling. The use of `IORead` is discussed
1040-
[here](./TUTORIAL.md#53-using-the-ioread-mechanism).
1042+
and more efficient than explicit polling. The use of `stream I/O` is discussed
1043+
[here](./TUTORIAL.md#53-using-the-stream-mechanism).
10411044

10421045
###### [Contents](./TUTORIAL.md#contents)
10431046

@@ -1099,7 +1102,7 @@ driver implements a `RecordOrientedUart` class, where data is supplied in
10991102
variable length records consisting of bytes instances. The object appends a
11001103
delimiter before sending and buffers incoming data until the delimiter is
11011104
received. This is a demo and is an inefficient way to use a UART compared to
1102-
IORead.
1105+
stream I/O.
11031106

11041107
For the purpose of demonstrating asynchronous transmission we assume the
11051108
device being emulated has a means of checking that transmission is complete
@@ -1159,7 +1162,7 @@ loop.run_until_complete(run())
11591162

11601163
###### [Contents](./TUTORIAL.md#contents)
11611164

1162-
## 5.3 Using the IORead Mechanism
1165+
## 5.3 Using the stream mechanism
11631166

11641167
This can be illustrated using a Pyboard UART. The following code sample
11651168
demonstrates concurrent I/O on one UART. To run, link Pyboard pins X1 and X2
@@ -1191,10 +1194,10 @@ loop.run_forever()
11911194
The supporting code may be found in `__init__.py` in the `uasyncio` library.
11921195
The mechanism works because the device driver (written in C) implements the
11931196
following methods: `ioctl`, `read`, `readline` and `write`. See
1194-
[Writing IORead device drivers](./TUTORIAL.md#54-writing-ioread-device-drivers)
1197+
[Writing streaming device drivers](./TUTORIAL.md#54-writing-streaming-device-drivers)
11951198
for details on how such drivers may be written in Python.
11961199

1197-
A UART can receive data at any time. The IORead mechanism checks for pending
1200+
A UART can receive data at any time. The stream I/O mechanism checks for pending
11981201
incoming characters whenever the scheduler has control. When a coro is running
11991202
an interrupt service routine buffers incoming characters; these will be removed
12001203
when the coro yields to the scheduler. Consequently UART applications should be
@@ -1227,9 +1230,9 @@ returned. See the code comments for more details.
12271230

12281231
###### [Contents](./TUTORIAL.md#contents)
12291232

1230-
## 5.4 Writing IORead device drivers
1233+
## 5.4 Writing streaming device drivers
12311234

1232-
The `IORead` mechanism is provided to support I/O to stream devices. Its
1235+
The `stream I/O` mechanism is provided to support I/O to stream devices. Its
12331236
typical use is to support streaming I/O devices such as UARTs and sockets. The
12341237
mechanism may be employed by drivers of any device which needs to be polled:
12351238
the polling is delegated to the scheduler which uses `select` to schedule the
@@ -1238,7 +1241,7 @@ multiple coros each polling a device, partly because `select` is written in C
12381241
but also because the coroutine performing the polling is descheduled until the
12391242
`poll` object returns a ready status.
12401243

1241-
A device driver capable of employing the IORead mechanism may support
1244+
A device driver capable of employing the stream I/O mechanism may support
12421245
`StreamReader`, `StreamWriter` instances or both. A readable device must
12431246
provide at least one of the following methods. Note that these are synchronous
12441247
methods. The `ioctl` method (see below) ensures that they are only called if

0 commit comments

Comments
 (0)