You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+102-8Lines changed: 102 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,9 +26,9 @@ assert out == (4, 5)
26
26
- Somewhat unusually, our syntax uses `yield` rather than `await`, but the behaviour is the same. Await another coroutine with `yield coro`. Await on multiple with `yield [coro1, coro2, ...]` (a 'gather' in asyncio terminology; a 'nursery' in trio terminology).
27
27
- An error in one coroutine will cancel all coroutines across the entire event loop.
28
28
- If the erroring coroutine is sequentially depended on by a chain of other coroutines, then we chain their tracebacks for easier debugging.
29
-
- Errors even propagate to and from synchronous operations ran in threads.
29
+
- Errors propagate to and from synchronous operations ran in threads.
30
30
- Can nest tinyio loops inside each other, none of this one-per-thread business.
31
-
- Ludicrously simple. No need for futures, tasks, etc. Here's the full API:
31
+
- Ludicrously simple. No need for futures, tasks, etc. Here's the entirety of the day-to-day API:
32
32
```python
33
33
tinyio.Loop
34
34
tinyio.run_in_thread
@@ -44,7 +44,7 @@ pip install tinyio
44
44
45
45
## Documentation
46
46
47
-
#### Loops
47
+
### Loops
48
48
49
49
Create a loop with `tinyio.Loop()`. It has a single method, `.run(coro)`, which consumes a coroutine, and which returns the output of that coroutine.
50
50
@@ -57,9 +57,10 @@ Coroutines can `yield` four possible things:
57
57
58
58
You can safely `yield` the same coroutine multiple times, e.g. perhaps four coroutines have a diamond dependency pattern, with two coroutines each depending on a single shared one.
59
59
60
-
#### Threading
60
+
### Threading
61
+
62
+
Blocking functions can be ran in threads using `tinyio.run_in_thread(fn, *args, **kwargs)`, which gives a coroutine you can `yield` on. Example:
61
63
62
-
Synchronous functions can be ran in threads using `tinyio.run_in_thread(fn, *args, **kwargs)`, which returns a coroutine you can `yield` on:
63
64
```python
64
65
import time, tinyio
65
66
@@ -75,13 +76,12 @@ loop = tinyio.Loop()
75
76
out = loop.run(foo(x=1)) # runs in one second, not three
76
77
assert out == [2, 2, 2]
77
78
```
78
-
The thread will call `fn(*args, **kwargs)`.
79
79
80
-
####Sleeping
80
+
### Sleeping
81
81
82
82
This is `tinyio.sleep(delay_in_seconds)`, which is a coroutine you can `yield` on.
83
83
84
-
####Error propagation
84
+
### Error propagation
85
85
86
86
If any coroutine raises an error, then:
87
87
@@ -91,6 +91,100 @@ If any coroutine raises an error, then:
91
91
92
92
This gives every coroutine a chance to shut down gracefully. Debuggers like [`patdb`](https://github.com/patrick-kidger/patdb) offer the ability to navigate across exceptions in an exception group, allowing you to inspect the state of all coroutines that were related to the error.
93
93
94
+
### Batteries-included
95
+
96
+
We ship batteries-included with a collection of standard operations, all built on top of just the functionality you've already seen.
97
+
98
+
<details><summary>Click to expand</summary>
99
+
100
+
```python
101
+
tinyio.add_done_callback tinyio.Semaphore
102
+
tinyio.AsCompleted tinyio.ThreadPool
103
+
tinyio.Barrier tinyio.timeout
104
+
tinyio.Event tinyio.TimeoutError
105
+
tinyio.Lock
106
+
```
107
+
None of these require special support from the event loop, they are all just simple implementations that you could have written yourself :)
Used as `yield {tinyio.add_done_callback(coro, success_callback)}`.
114
+
115
+
This wraps `coro` so that `success_callback(out)` is called on its output once it completes. Note the `{...}` above, indicating calling this in nonblocking fashion (otherwise you could just directly call the callbacks yourself).
116
+
117
+
---
118
+
119
+
-`tinyio.AsCompleted({coro1, coro2, ...})`
120
+
121
+
This schedules multiple coroutines in the background (like `yield {coro1, coro2, ...}`), and then offers their results in the order they complete.
122
+
123
+
This is iterated over in the following way, using its `.done()` and `.get()` methods:
This has a single method `barrier.wait()`, which is a coroutine you can `yield` on. Once `value` many coroutines have yielded on this method then it will unblock.
136
+
137
+
---
138
+
139
+
-`tinyio.Event()`
140
+
141
+
This has a method `.wait()`, which is a coroutine you can `yield` on. This will unblock once its `.set()` method is called (typically from another coroutine). It also has a `is_set()` method for checking whether it has been set.
142
+
143
+
---
144
+
145
+
-`tinyio.Lock()`
146
+
147
+
This is just a convenience for`tinyio.Semaphore(value=1)`, see below.
148
+
149
+
---
150
+
151
+
-`tinyio.Semaphore(value)`
152
+
153
+
This manages an internal counter that is initialised at `value`, is decremented when entering a region, and incremented when exiting. This blocks if this counter is at zero. In this way, at most `value` coroutines may acquire the semaphore at a time.
154
+
155
+
This is used as:
156
+
```python
157
+
semaphore = Semaphore(value)
158
+
159
+
...
160
+
161
+
with (yield semaphore()):
162
+
...
163
+
```
164
+
165
+
---
166
+
167
+
-`tinyio.timeout(coro, timeout_in_seconds)`
168
+
169
+
This is a coroutine you can `yield` on, used as`output, success = yield tinyio.timeout(coro, timeout_in_seconds)`.
170
+
171
+
This runs `coro`for at most `timeout_in_seconds`. If it succeeds in that time then the pair `(output, True)`is returned . Else this will return`(None, False)`, and`coro` will be halted by raising `tinyio.TimeoutError` inside it.
172
+
173
+
---
174
+
175
+
-`tinyio.ThreadPool(max_threads)`
176
+
177
+
This is equivalent to making multiple `tinyio.run_in_thread` calls, but will limit the number of threads to at most `max_threads`. Additional work after that will block until a thread becomes available.
178
+
179
+
This has two methods:
180
+
181
+
-`.run_in_thread(fn, *args, **kwargs)`, which is a coroutine you can `yield` on. This is equivalent to `yield tinyio.run_in_thread(fn, *args, **kwargs)`.
182
+
-`.map(fn, xs)`, which is a coroutine you can `yield` on. This is equivalent to `yield [tinyio.run_in_thread(fn, x) for x in xs]`.
0 commit comments