2
2
3
3
This document aims to explain the operation of ` uasyncio ` as I understand it. I
4
4
did not write the library so the information presented is a result of using it,
5
- also studying the code, experiment and inference. There may be errors, in which
6
- case please raise an issue. None of the information here is required to use the
7
- library.
5
+ studying the code, experiment and inference. There may be errors, in which case
6
+ please raise an issue. None of the information here is required to use the
7
+ library: it is intended to satisfy the curiosity of scheduler geeks .
8
8
9
- It assumes a good appreciation of the use of ` uasyncio ` . Familiarity with
9
+ Where the versions differ, the explanation relates to the ` fast_io ` version.
10
+ Differences are largely in ` __init__.py ` : the scheduling algorithm in ` core.py `
11
+ is little changed.
12
+
13
+ This doc assumes a good appreciation of the use of ` uasyncio ` . Familiarity with
10
14
Python generators is also recommended, in particular the use of ` yield from `
11
15
and appreciating the difference between a generator and a generator function:
12
16
@@ -19,12 +23,11 @@ def gen_func(n): # gen_func is a generator function
19
23
my_gen = gen_func(7 ) # my_gen is a generator
20
24
```
21
25
22
- The code for ` uasyncio ` may be found in micropython-lib in the following
23
- directories:
26
+ The code for the ` fast_io ` variant of ` uasyncio ` may be found in:
24
27
25
28
```
26
- uasyncio/uasyncio /__init__.py
27
- uasyncio.core/uasyncio /core.py
29
+ fast_io /__init__.py
30
+ fast_io /core.py
28
31
```
29
32
30
33
# Generators and coroutines
@@ -101,7 +104,7 @@ The following subclasses exist:
101
104
interface.
102
105
* ` IOWrite ` Causes an interface to be polled for ready to accept data. ` .arg `
103
106
is the interface.
104
- * ` IOReadDone ` These stop polling of an interface.
107
+ * ` IOReadDone ` These stop polling of an interface (in ` .arg ` ) .
105
108
* ` IOWriteDone `
106
109
107
110
The ` IO* ` classes are for the exclusive use of ` StreamReader ` and ` StreamWriter `
@@ -113,11 +116,14 @@ The file `core.py` defines an `EventLoop` class which is subclassed by
113
116
` PollEventLoop ` in ` __init__.py ` . The latter extends the base class to support
114
117
stream I/O. In particular ` .wait() ` is overridden in the subclass.
115
118
116
- The ` EventLoop ` maintains two queues, ` .runq ` and ` .waitq ` . Tasks are appended
117
- to the bottom of the run queue and retrieved from the top; in other words it is
118
- a First In First Out (FIFO) queue. Tasks on the wait queue are sorted in order
119
- of the time when they are to run, the task having the soonest time to run at
120
- the top.
119
+ The ` fast_io ` ` EventLoop ` maintains three queues, ` .runq ` , ` .waitq ` and ` .ioq ` ,
120
+ although ` .ioq ` is only instantiated if it is specified. Official ` uasyncio `
121
+ does not have ` .ioq ` .
122
+
123
+ Tasks are appended to the bottom of the run queue and retrieved from the top;
124
+ in other words it is a First In First Out (FIFO) queue. The I/O queue is
125
+ similar. Tasks on the wait queue are sorted in order of the time when they are
126
+ to run, the task having the soonest time to run at the top.
121
127
122
128
When a task issues ` await asyncio.sleep(t) ` or ` await asyncio.sleep_ms(t) ` and
123
129
t > 0 the task is placed on the wait queue. If t == 0 it is placed on the run
@@ -140,7 +146,8 @@ iterates to the next entry. If it is a task, it runs then either yields or
140
146
raises an exception. If it yields the return type is examined as described
141
147
above. If the task yields with a zero delay it will be appended to the run
142
148
queue, but as described above it will not be rescheduled in this pass through
143
- the queue.
149
+ the queue. If it yields a nonzero delay it will be added to ` .waitq ` (it has
150
+ already been removed from ` .runq ` ).
144
151
145
152
Once every task which was initially on the run queue has been scheduled, the
146
153
queue may or may not be empty depending on whether tasks yielded a zero delay.
@@ -164,10 +171,15 @@ the run queue - the task is simply not rescheduled.
164
171
If an unhandled exception occurs in a task this will be propagated to the
165
172
caller of ` run_forever() ` or ` run_until_complete ` a explained in the tutorial.
166
173
167
- # Stream I/O
174
+ ## Task Cancellation
168
175
169
- This description of stream I/O is based on my code rather than the official
170
- version.
176
+ The ` cancel ` function uses ` pend_throw ` to pass a ` CancelledError ` to the coro
177
+ to be cancelled. The generator's ` .throw ` and ` .close ` methods cause the coro
178
+ to execute code immediately. This is incorrect behaviour for a de-scheduled
179
+ coro. The ` .pend_throw ` method causes the exception to be processed the next
180
+ time the coro is scheduled.
181
+
182
+ # Stream I/O
171
183
172
184
Stream I/O is an efficient way of polling stream devices using ` select.poll ` .
173
185
Device drivers for this mechanism must provide an ` ioctl ` method which reports
0 commit comments