asyncopenai-concurrency-httpx-pool

Solid

Raise real concurrency in asyncio LLM batch scorers built on the OpenAI SDK (AsyncOpenAI, including OpenAI-compatible providers like DeepSeek). Use when: (1) raising an asyncio.Semaphore above ~100 produces no throughput gain, (2) a batch pipeline saturates near 100 in-flight requests despite a larger semaphore, (3) planning a high-concurrency campaign against a provider with no hard rate limit (DeepSeek v4-flash tolerates 2000+ in flight). Root cause: AsyncOpenAI's default httpx pool caps max_connections at 100, silently bottlenecking any larger semaphore — you must pass a custom http_client with httpx.Limits sized to the semaphore.

AI & Automation 57 stars 0 forks Updated 5 days ago MIT

Install

View on GitHub

Quality Score: 90/100

Stars 20%
59
Recency 20%
100
Frontmatter 20%
70
Documentation 15%
100
Issue Health 10%
80
License 10%
100
Description 5%
100

Skill Content

# AsyncOpenAI Concurrency: the Hidden httpx Pool Cap ## Problem Async batch scorers typically gate concurrency with `asyncio.Semaphore(N)`. Raising N above ~100 silently does nothing: the OpenAI SDK's default httpx transport caps the connection pool at `max_connections=100`, so excess tasks queue inside httpx instead of reaching the provider. The semaphore looks like the throttle but is not the binding constraint — there is no error, just a throughput ceiling. ## Context / Trigger Conditions - `asyncio.Semaphore(N)` with N > 100 around `client.chat.completions.create` shows the same throughput as N = 100 - Client constructed as `AsyncOpenAI(api_key=..., base_url=...)` with no `http_client` argument (the default transport) - Provider is known to allow high concurrency (DeepSeek v4-flash: ~2500) - Symptom check: requests-in-flight measured at the server never exceeds ~100 ## Solution Size the httpx pool to the semaphore when constructing the client: ```python import httpx from openai import AsyncOpenAI CONCURRENCY = 2000 client = AsyncOpenAI( api_key=..., base_url="https://api.deepseek.com", http_client=httpx.AsyncClient(limits=httpx.Limits( max_connections=CONCURRENCY, max_keepalive_connections=CONCURRENCY))) sem = asyncio.Semaphore(CONCURRENCY) ``` Both edits are required; either alone caps the other. Keep the per-request retry loop — at high concurrency transient failures are more likely, and the retry envelope is what turns them into non...

Details

Author
kennethkhoocy
Repository
kennethkhoocy/applied-micro-skills
Created
6 days ago
Last Updated
5 days ago
Language
Python
License
MIT

Integrates with

Similar Skills

Semantically similar based on skill content — not just same category