Parallel fan-out with asyncio.gather

Sentiment and summary and emotion have no data dependencies on each other. Running them sequentially means waiting four seconds for sentiment, three for summary, two for emotion. Total: nine seconds. Running them in parallel with asyncio.gather brings total latency down to four seconds, the slowest task.

agent/graph.py
python
import asyncio


async def _run_parallel(text: str, tasks: list[str]) -> dict:
    """Fan out independent tasks with asyncio.gather."""
    fns = [TASK_REGISTRY[name] for name in tasks]
    results = await asyncio.gather(
        *(fn(text) for fn in fns),
        return_exceptions=True,
    )
    out: dict = {"errors": {}}
    for name, result in zip(tasks, results):
        if isinstance(result, Exception):
            out["errors"][name] = str(result)
        else:
            out[name] = result
    return out

return_exceptions=True is the key detail. Without it, one failing task cancels every other task in the gather. With it, you collect exceptions alongside successes and report them per task.

When tasks depend on each other. If the summary task benefits from seeing the extracted entities, or a secondary classifier conditions on the sentiment score, the sequential graph gives you a place to pass state between nodes. Parallel fan-out is the right default for independent tasks. A real system often mixes both: a parallel fan-out for the cheap tasks, then a sequential phase for the ones that depend on earlier outputs.

Quiz: Quiz

Loading practice…

Checkpoint: Agent graph checkpoint

Loading practice…