How does Uvicorn use asyncio to handle thousands of concurrent connections?

Tests async concurrency and the GIL. Great answers cover the event loop suspending coroutines at await, Uvicorn interleaving connections, and multi-process workers for parallelism. Red flag: claiming asyncio uses threads per request or bypasses the GIL.
What's really being asked
This question probes whether you understand how Python achieves concurrency without parallelism by default, and how an ASGI server leverages that model to handle high connection counts. Interviewers want to see that you know the event loop is not magical threading but explicit cooperative multitasking, and that you recognize the GIL boundary that forces multi-process architectures for CPU scaling.
The full answer
First, define the event loop as the core of asyncio, a single-threaded construct that uses selectors like epoll or kqueue to multiplex I/O and schedules coroutines. Second, explain that when FastAPI awaits an external call such as a database query or HTTP request, the coroutine yields control and the loop immediately switches to another ready task, allowing one process to interleave thousands of connections. Third, state that Uvicorn creates and runs this loop, accepting TCP connections and translating them into ASGI event dictionaries that it pushes into the FastAPI application. Fourth, emphasize that because of the GIL, only one thread of Python bytecode executes at a time per process, so a single event loop cannot utilize multiple CPU cores for computation; therefore Uvicorn relies on multiple worker processes, typically four to eight per machine, to achieve true parallelism across cores.
The mistakes people make
A major red flag is claiming that asyncio spawns a thread per connection or that it removes the GIL. Another is describing the event loop as a separate thread that runs in the background; the loop runs in the main thread and callbacks execute there. Candidates also err by saying Python coroutines run in parallel on multiple cores within one process, which is impossible for standard CPython bytecode. Finally, confusing sync WSGI threading models with ASGI async models suggests a shallow understanding of the stack.
What usually comes next
An interviewer might ask what happens if you call a blocking library like requests or SQLAlchemy sync inside an async path operation. They could also ask how you would profile event loop lag, or why you might choose Hypercorn over Uvicorn. Another common tangent is how to run CPU-bound work inside an async endpoint without stalling the loop, which leads to ProcessPoolExecutor or offloading to a task queue.
A concrete example
Imagine a FastAPI endpoint that awaits an async PostgreSQL driver such as asyncpg to fetch a user. When the query hits the network, asyncpg yields to the event loop. Uvicorn, which owns that loop, immediately begins parsing headers from a new WebSocket connection. Once the database packet returns, the loop resumes the original endpoint coroutine and Uvicorn sends the ASGI http.response.start event back to the client. If the endpoint instead ran a synchronous bcrypt hash without using run_in_executor, the entire loop would freeze for fifty milliseconds and every concurrent connection would stall.
Interview question
When a FastAPI endpoint awaiting asyncpg is suspended during a database query, how can Uvicorn process another incoming connection in the same worker process?
- a.The GIL is released during the network wait, allowing a second Python thread in the same process to execute the new connection's handler.
- b.asyncio transparently migrates the suspended coroutine to a background thread so the main event loop remains free.
- c.Uvicorn spawns a lightweight thread for each connection, and the OS scheduler interleaves them while the database coroutine blocks.
- d.The event loop yields the coroutine at the await, registers the socket with epoll or kqueue, and schedules the new connection's coroutine on the same thread.Correct
Why? this is the answer
The correct answer describes cooperative multitasking: the event loop suspends the coroutine at await and interleaves I/O-bound tasks on a single thread. Distractor A is wrong because Uvicorn does not use multiple Python threads to handle requests; concurrency comes from the loop scheduling coroutines, not from threading or GIL behavior.
Just read this? Test yourself on what you have been reading.
Read the original → fastapi.tiangolo.com
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on python — each one lists the topics its interview covers.
See open roles