trio
Friendly Python library for async concurrency using structured concurrency principles — nurseries replace callbacks/futures with scoped task management where parent waits for all children. trio features: trio.open_nursery() for task groups, automatic cancellation propagation, checkpoint system for cooperative multitasking, trio.sleep(), trio.move_on_after()/fail_after(), MemoryChannel for async communication, trio.to_thread.run_sync() for thread offloading, trio.from_thread utilities, atomic checkpoint guarantees (no partial execution), DTRT (Do The Right Thing) philosophy for error handling, and trio-asyncio bridge for asyncio compatibility.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Async concurrency library. Structured concurrency prevents resource leaks from cancelled tasks. Nursery ensures all child tasks complete or all cancel — no orphaned background tasks. Cancellation propagates correctly through finally blocks.
⚡ Reliability
Best When
New async Python projects where correctness and structured concurrency matter most, especially when not relying on asyncio-specific libraries.
Avoid When
asyncio ecosystem integration (use anyio for compat), FastAPI/Starlette applications, or projects needing wide async library compatibility.
Use Cases
- • Agent nursery concurrency — async with trio.open_nursery() as nursery: nursery.start_soon(fetch, url1); nursery.start_soon(process, item) — structured; agent runs concurrent tasks where all complete or all cancel on exception; nursery is the fundamental concurrency primitive; exception in child cancels all siblings and propagates to parent
- • Agent timeout with cleanup — with trio.move_on_after(30) as cancel_scope: await slow_operation(); if cancel_scope.cancelled_caught: logger.warning('timed out') — timeout; agent wraps operations with deadline; move_on_after continues after timeout; fail_after raises trio.TooSlowError; cancellation triggers finally blocks for cleanup
- • Agent async channels — send_channel, receive_channel = trio.open_memory_channel(max_buffer_size=10); async with trio.open_nursery() as n: n.start_soon(producer, send_channel); n.start_soon(consumer, receive_channel) — channels; agent implements producer/consumer with bounded buffer; channel close propagates to receiver as EndOfChannel
- • Agent thread integration — await trio.to_thread.run_sync(blocking_io_fn, arg, cancellable=True) — thread offload; agent runs blocking functions in thread pool without blocking trio event loop; cancellable=True allows trio to cancel thread (SIGINT-safe); limiter= for concurrency control
- • Agent checkpointing — async def my_task(): for item in large_list: process(item); await trio.sleep(0) — yield point — periodic checkpoint; agent yields control to trio scheduler at regular intervals; trio.sleep(0) is minimal checkpoint; prevents task monopolizing scheduler for CPU-bound loops
Not For
- • asyncio ecosystem — most Python async libraries (aiohttp, asyncpg, motor) require asyncio; trio requires trio-asyncio bridge for compatibility which adds overhead
- • Production asyncio services — FastAPI, Starlette, uvicorn all use asyncio; trio integration is via bridge
- • Simple scripts needing wide library compatibility — asyncio has much larger ecosystem of compatible libraries
Interface
Authentication
No auth — async concurrency library.
Pricing
trio is dual licensed MIT/Apache 2.0. Free for all use.
Agent Metadata
Known Gotchas
- ⚠ Nursery exceptions use ExceptionGroup — if multiple nursery children raise, trio raises ExceptionGroup; Python 3.11+ has native except*; older Python needs exceptiongroup backport (trio installs automatically); agent code: use except* SomeError: or handle ExceptionGroup.exceptions; single child exception unwrapped only in some cases
- ⚠ trio.run() cannot be called from inside trio — calling trio.run() inside running trio raises RuntimeError; agent code: use trio.from_thread.run_sync() or run() to enter from sync code once at top level; nested trio.run() not supported; use nurseries for nested task groups
- ⚠ Checkpoint required for cancellation to work — trio can only cancel tasks at checkpoint (trio.sleep(), socket operations, etc.); CPU-bound loops without checkpoints cannot be cancelled; agent code with long loops: add await trio.sleep(0) periodically; trio.testing.MockClock for testing time-based code
- ⚠ MemoryChannel is bounded — open_memory_channel(max_buffer_size=0) is unbuffered (send blocks until receive); max_buffer_size=math.inf is unbounded; agent code: choose buffer size carefully; unbuffered for tight producer/consumer; bounded for flow control; send() blocks when full (use nursery task for producer)
- ⚠ Cleanup must use finally or __aexit__ — trio cancellation triggers Cancelled exception in awaiting code; code in finally blocks runs during cancellation; agent code: use 'async with' and 'finally' for all cleanup; resource acquisition inside try: ... finally: resource.close() pattern; shield=True on cleanup scope if cleanup must complete
- ⚠ trio does not work with asyncio libraries directly — aiohttp, asyncpg, motor require asyncio event loop; trio has different event loop; agent code needing asyncio libs: use trio-asyncio (pip install trio-asyncio) bridge or switch to anyio for backend compatibility; anyio is preferred compatibility layer
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for trio.
Scores are editorial opinions as of 2026-03-06.