micropython-samples/uasyncio_iostream/README.md

162 wiersze
5.4 KiB
Markdown
Czysty Zwykły widok Historia

2019-12-04 17:29:00 +00:00
# 1. Changes to usayncio
2019-12-04 17:29:00 +00:00
This archive contains suggestions for changes to new `uasyncio`.
## 1.1 Changes implemented
2019-11-21 11:29:16 +00:00
1. Implement as a Python package.
2. Implement synchronisation primitives as package modules to conserve RAM.
2019-12-02 13:53:29 +00:00
3. `Primitive` class has methods common to most synchronisation primitives.
Avoids the need for primitives to access the task queue directly.
2019-12-02 13:53:29 +00:00
4. Add `.priority` method to `Stream` class. Enables I/O to be handled at high
priority on a per-device basis.
2019-12-02 13:53:29 +00:00
5. Rename task queue class `TQueue` to avoid name clash with Queue primitive.
2019-12-04 17:29:00 +00:00
### Minor changes
2019-11-21 11:29:16 +00:00
1. Move `StreamReader` and `StreamWriter` assignments out of legacy section of
code: these classes exist in `asyncio` 3.8.
2. `.CreateTask` produces an assertion fail if called with a generator function.
Avoids obscure traceback if someone omits the parens.
2019-11-21 11:29:16 +00:00
3. Add machine readable version info. Useful in testing.
2019-12-04 17:29:00 +00:00
## 1.2 Suggested changes
I haven't implemented these.
1. Make `Event.set` capable of being triggered from an ISR.
2. Implement `wait_for_ms` as per V2.
# 2. CPython-compatible synchronisation primitives
2019-11-23 16:38:58 +00:00
These aim to work efficiently with the new version. All are separate modules to
2019-12-04 17:29:00 +00:00
conserve RAM. Items 1-4 subclass `uasyncio.Primitive`.
2019-12-03 05:47:14 +00:00
1. `Event`: Moved to separate module.
2. `Lock`: Kevin Köck's solution.
3. `Queue`: Paul's solution adapted for efficiency.
2019-11-21 11:29:16 +00:00
4. `Semaphore`: Also implements `BoundedSemaphore`.
5. `Condition`.
2019-12-04 17:29:00 +00:00
# 3. Other primitives
2019-11-23 16:38:58 +00:00
Included as examples of user-contributed primitives - see final section.
2019-11-21 11:29:16 +00:00
1. `Message`: Awaitable `Event` subclass with a data payload.
2019-12-03 05:47:14 +00:00
2. `Barrier`: Multiple tasks wait until all are either waiting on a Barrier
instance or have triggered the instance without waiting. Similar to `gather`
without the controlling coro: a barrier is shared between peers and may be
used in loops.
2019-12-04 17:29:00 +00:00
# 4. Test scripts
Hopefully these are self-documenting on import.
2019-12-04 17:29:00 +00:00
1. `prim_test.py` Tests for synchronisation primitives. Runs on MicroPython and
CPython V3.5-3.8. Demonstrates that MicroPython primitives behave similarly to
native CPython ones.
2. `test_fast_scheduling.py` Demonstrates difference between normal and priority
I/O scheduling. Runs on Pyboard.
3. `ms_timer.py` and `ms_timer_test.py` A practical use of priority scheduling to
implement a timer with higher precision than `asyncio.sleep_ms`. Runs on Pyboard.
2019-12-07 06:24:01 +00:00
4. `test_can.py` Demonstrates differences in behaviour between CPython 3.8 and
MicroPython. See code comments.
2019-12-04 17:29:00 +00:00
# 5. CPython compatibility of user primitives
2019-11-21 11:29:16 +00:00
2019-12-04 17:29:00 +00:00
`Message` is common to CPython and MicroPython.
2019-11-21 11:29:16 +00:00
There are two implementations of `Barrier` with the same functionality: a CPython
version and a MicroPython version with specific optimisations. The `Barrier` class
is loosely based on
[a Microsoft concept](https://docs.microsoft.com/en-us/windows/win32/sync/synchronization-barriers).
2019-12-04 17:29:00 +00:00
## 5.1 Directory structure of primitives
2019-11-21 11:29:16 +00:00
MicroPython optimised primitives are in `uasyncio/`. Primitives compatible with
`asyncio` are in `primitives/`.
2019-11-23 16:38:58 +00:00
2019-12-04 17:29:00 +00:00
# 6. Future uasyncio implementations
2019-11-23 16:38:58 +00:00
If part of `uasyncio` is to be implemented in C, it would be good if the following
capabilities were retained:
2019-11-23 16:38:58 +00:00
1. The ability to subclass the `asyncio` compatible primitives.
2. The ability to subclass `uasyncio.Primitive` (or provide other access to that
functionality).
3. A means of replacing the timebase by one based on the RTC for low power
applications.
4. A means of creating awaitable classes (e.g. `__iter__`).
2019-12-04 17:29:00 +00:00
# 7. Revisiting topics discussed via email
I am revising my tutorial to promote Python 3.8 syntax and to verify that code
samples run under MicroPython and CPython 3.8. I'm removing references to event
loop methods except for one minor section. This describes how to code for
compatibility with CPython versions 3.5-3.7.
2019-12-04 17:29:00 +00:00
Here are my observations on issues previously discussed.
2019-12-04 17:29:00 +00:00
## 7.1 Awaitable classes
2019-12-04 17:29:00 +00:00
I now have portable code which produces no syntax errors under CPython 3.8. It
is arguably hacky but a similar hack is required for V2. Nobody has complained.
```python
up = False # Running under MicroPython?
try:
import uasyncio as asyncio
up = True # Or can use sys.implementation.name
except ImportError:
import asyncio
async def times_two(n): # Coro to await
await asyncio.sleep(1)
return 2 * n
class Foo():
def __await__(self):
res = 1
for n in range(5):
print('__await__ called')
if up: # MicroPython
res = yield from times_two(res)
else: # CPython
res = yield from times_two(res).__await__()
return res
__iter__ = __await__ # MicroPython compatibility
async def bar():
foo = Foo() # foo is awaitable
print('waiting for foo')
res = await foo # Retrieve value
print('done', res)
asyncio.run(bar())
```
2019-12-04 17:29:00 +00:00
## 7.2 run_forever() behaviour
In an email I commented that the following code sample never terminates under
CPython 3.8, whereas under MicroPython it does:
```python
try:
import asyncio
except ImportError:
import uasyncio as asyncio
async def test():
print("test")
for _ in range(2):
await asyncio.sleep(0)
print('test2')
await asyncio.sleep(0.5)
print('Done')
loop=asyncio.get_event_loop()
loop.create_task(test())
loop.run_forever()
# asyncio.run(test())
```
While the observation is true, using the preferred (commented out) syntax it
terminates in CPython 3.8 and in MicroPython. My view is that it's not worth
fixing.