Uvicorn

정지웅·2025년 4월 24일

Uvicorn is an ASGI web server implementation for Python.

Uvicorn 실행 흐름

Uvicorn은 ASGI App을 실행시켜주는 ASGI server입니다.
Uvicorn 덕에 Non-Blocking I/O를 통한 비동기 처리가 가능하고, 이는 Uvicorn 내부의 이벤트 루프를 통해서 실현이 가능합니다.
클라이언트의 요청이 왔을 때, 어떻게 실행되는지 흐름대로 적어보겠습니다.

  1. 클라이언트가 요청을 보내고, Uvicorn Server가 받음.
  2. Uvicorn이 이벤트 루프를 만들고 실행함.
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(app(scope, receive, send)) # app 함수는 FastAPI 내부의 __call__ 함수를 호출합니다.

* asyncio의 기본 이벤트 루프와, uvloop의 libuv(Node.js의 그 이벤트 루프) 기반의 이벤트 루프를 선택할 수 있습니다.

  1. FastAPI의 비즈니스 로직 실행중, 내부에서 코루틴 생성
coroutine_obj = handler(**kwargs)
result = await coroutine_obj

* handler는 async def 함수이고, coroutine_obj는 코루틴 객체입니다.

  1. await를 만나게 되면, 파이썬 내부적으로 await 뒤에 있는 코루틴 객체의 __await__() 함수 실행.
coro = some_async_func()
awaitable = coro.__await__()
  1. 이벤트 루프가 awaitable(iterator)를 task로 감싸고 태스크 큐에 등록(스케줄링)함.
  2. 이벤트 루프는 이 iterator를 .send() or .next() 하며 실행함.

이벤트 루프 실행 흐름

  1. _ready 큐 순회
  • 실행 준비된 Task
  1. _scheduled 큐 순회
  • 지연 예약(sleep())
  1. selector 큐 순회
  • OS-level I/O 대기(socket, http)

-> 대기하던 큐들이 작업이 완료되면 콜백으로 Task.wakeup() or Future.set_result() 등을 통해서 _ready 큐로 들어가 남은 작업은 완료하게 됨.

0개의 댓글