Complete worked example
python
import asyncio
import httpx
from fastapi import FastAPI
def inspect_example(values):
app = FastAPI()
active = peak = 0
@app.get("/double/{value}")
async def double(value: int):
nonlocal active, peak
active += 1
peak = max(peak, active)
try:
await asyncio.sleep(0)
return {"value": value * 2}
finally:
active -= 1
async def run():
budget = asyncio.Semaphore(2)
transport = httpx.ASGITransport(app=app)
async with httpx.AsyncClient(transport=transport, base_url="http://lesson.test") as client:
async def one(value):
async with budget:
response = await client.get(f"/double/{value}")
response.raise_for_status()
return response.json()["value"]
return await asyncio.gather(*(one(value) for value in values))
results = asyncio.run(run())
return {"values": results, "peak": peak}- Reasoning
- Each endpoint increments an active counter, yields control and then returns a transformed identifier. A finally block decrements the counter. The client wraps each request in the semaphore and awaits asyncio.gather, which returns results in input order even when work overlaps. The helper reports returned values and the peak active count. Those observations show both the data contract and the concurrency budget. The synchronous outer helper uses asyncio.run only as a standalone lab entry point; calling it inside an already running event loop would require a different integration.