Appels asynchrones avec HTTPX dans les points de terminaison FastAPI
Préoccupations concernant l'utilisation de ThreadPoolExecutor dans FastAPI
Vous a exprimé des inquiétudes quant à l'impact de l'utilisation de concurrent.futures.ThreadPoolExecutor dans un point de terminaison FastAPI, en particulier en ce qui concerne la création de threads, la famine de l'hôte et les plantages d'applications. Ces préoccupations sont valables car une création excessive de threads peut solliciter les ressources et potentiellement entraîner des problèmes de performances.
Recommandation : API HTTPX Async
Pour éviter ces pièges potentiels, il est recommandé de utilisez les capacités asynchrones de la bibliothèque HTTPX au lieu de concurrent.futures.ThreadPoolExecutor. HTTPX fournit une API asynchrone efficace qui vous permet d'effectuer des requêtes HTTP sans avoir besoin d'une gestion explicite des threads. Cette approche offre plusieurs avantages :
Exemple de travail
Le code suivant L'extrait montre comment implémenter des requêtes HTTP asynchrones avec HTTPX dans un point de terminaison FastAPI :
from fastapi import FastAPI, Request from contextlib import asynccontextmanager import httpx import asyncio URLS = ['https://www.foxnews.com/', 'https://edition.cnn.com/', 'https://www.nbcnews.com/', 'https://www.bbc.co.uk/', 'https://www.reuters.com/'] @asynccontextmanager async def lifespan(app: FastAPI): # customise settings limits = httpx.Limits(max_keepalive_connections=5, max_connections=10) timeout = httpx.Timeout(5.0, read=15.0) # 15s timeout on read. 5s timeout elsewhere. # Initialise the Client on startup and add it to the state async with httpx.AsyncClient(limits=limits, timeout=timeout) as client: yield {'client': client} # The Client closes on shutdown app = FastAPI(lifespan=lifespan) async def send(url, client): return await client.get(url) @app.get('/') async def main(request: Request): client = request.state.client tasks = [send(url, client) for url in URLS] responses = await asyncio.gather(*tasks) return [r.text[:50] for r in responses] # for demo purposes, only return the first 50 chars of each response
Alternative : diffuser des réponses en continu pour éviter l'utilisation de la RAM
Si vous lisez l'intégralité du corps de la réponse dans la RAM est un problème, envisagez d'utiliser les réponses Streaming de HTTPX avec StreamingResponse de FastAPI :
... # (same as previous code snippet) async def iter_content(responses): for r in responses: async for chunk in r.aiter_text(): yield chunk[:50] # for demo purposes, return only the first 50 chars of each response and then break the loop yield '\n\n' break await r.aclose() @app.get('/') async def main(request: Request): client = request.state.client tasks = [send(url, client) for url in URLS] responses = await asyncio.gather(*tasks) return StreamingResponse(iter_content(responses), media_type='text/event-stream')
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!