| Name | Size |
|---|---|
| .github/workflows/main.yml | 853B |
| LICENSE | 1072B |
| README.md | 2404B |
| pyproject.toml | 426B |
| tests/test_compat.py | 1924B |
| tests/test_core.py | 3969B |
| tests/test_multiplex.py | 4971B |
| tests/test_signals.py | 655B |
| tests/test_subprocess.py | 860B |
| tests/test_threads.py | 903B |
| tests/utils.py | 765B |
| xiio/__init__.py | 561B |
| xiio/compat.py | 1542B |
| xiio/core.py | 5112B |
| xiio/multiplex.py | 2855B |
| xiio/signals.py | 1021B |
| xiio/subprocess.py | 1152B |
| xiio/threads.py | 1920B |
xiio - really simple async runtime
xiio (Ξ-I/O) is yet another async runtime for Python, like asyncio or trio. Both of these libraries have ~10k lines of code, while this one has a few hundred lines. So I guess it is fair to say that it is really simple.
Usage
import sys
import xiio
async def greet(name):
await xiio.sleep(len(name) / 10)
print(f'Hello, {name}!')
async def main():
async with xiio.timeout(10):
name1 = (await xiio.read(sys.stdin, 32)).decode()
name2 = (await xiio.read(sys.stdin, 32)).decode()
await xiio.gather([
greet(name1),
greet(name2),
])
xiio.run(main())
Structured Concurrency
Similar to nurseries in
trio
and task groups in
asyncio,
xiio provides a low level primitive that controls the lifetime of subtasks.
For example, gather() is just a higher level abstraction on top of that:
async def gather(coros):
async with TaskGroup() as tg:
tasks = [tg.add_task(coro) for coro in coros]
return [task.result for task in tasks]
Task groups in xiio have the following properties:
- All subtasks are guaranteed to have finished when the task group exits.
- Subtasks are not started immediately. They have a chance to get started the next time the main task awaits.
- If any task in a task group raises an exception, a
xiio.CancelledErroris raised in all other tasks. The tasks are then responsible for cleaning up quickly. They may still await async functions if necessary. - Any exceptions that are raised after cancellation are lost. Only the first one is raised after cleanup is done.
- Tasks are removed from the task group once they are done. If you need their
results, keep the reference that is returned by
TaskGroup.add_task(). - It is possible to add new tasks while the task group is already running, and even after cancellation.
Design
I spent quite some time creating meaningful commits. So if you want to understand why all the individual pieces are there and how they fit together, I encourage you to check the commit history.