Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Concurrency & Asyncio

When waiting for task results from asynchronous runtimes (such as FastAPI, Sanic, or standard asyncio applications), using the blocking .result() method will block Python’s main thread and freeze the event loop.

To prevent this, Pyroxide provides the non-blocking asynchronous await API.

Non-Blocking event loop awaiting (result_async)

By awaiting result_async(), you temporarily yield control back to Python’s asyncio event loop, allowing it to process other concurrent requests while the Rust pool executes the task:

import asyncio
from pyroxide import task

@task
def cpu_bound_task(x: int) -> int:
    return sum(i * i for i in range(x))

async def request_handler():
    handle = cpu_bound_task(10_000_000)
    
    # Non-blocking await
    result = await handle.result_async()
    print("Task result:", result)

async def main():
    # Runs the handler concurrently with other asyncio jobs
    await asyncio.gather(
        request_handler(),
        asyncio.sleep(0.1) # Event loop remains responsive!
    )

asyncio.run(main())

Under the Hood

The result_async method offloads Pyroxide’s native condvar blocking check to the asyncio event loop’s default ThreadPoolExecutor. This keeps the main thread running the event loop while background OS threads wait for the completion signal from Rust.