FastAPI 비동기(async)와 병행 처리¶
개요¶
API가 DB 조회나 LLM 호출처럼 시간이 걸리는 I/O 작업을 만나면, 그 작업이 끝날 때까지 서버 전체가 멈추게 만들면 안 되겠죠. FastAPI는 Python의 비동기 코드(async/await)를 자연스럽게 지원해서, 한 요청이 대기하는 동안 다른 요청을 계속 처리할 수 있게 해요. 그런데 FastAPI의 비동기는 "무조건 async def를 써야 한다"는 단순한 규칙이 아니라, 함수 정의 방법에 따라 처리 방식이 달라지는 구조라서 이 차이를 이해하는 게 중요합니다.
핵심 개념¶
async/await와 코루틴¶
최신 Python은 코루틴(coroutine)이라는 개념으로 비동기 코드를 지원해요. 비동기 코드는 "어떤 시점에 다른 곳에서 끝날 무언가를 기다려야 한다"고 프로그램에 알려주는 방식이에요. await를 쓰려면 그 코드는 async def로 선언된 함수 안에 있어야 합니다. 예를 들어 await some_library()처럼 호출하라고 안내하는 서드파티 라이브러리를 쓴다면, path operation 함수도 async def로 선언하면 돼요.
def와 async def의 차이¶
핵심은 이거예요. @app.get 같은 path operation 함수를 일반 def로 선언하면, FastAPI는 그 함수를 외부 스레드풀(threadpool)에서 실행하고 그 결과를 다시 기다립니다. async def로 선언하면 이벤트 루프에서 직접 await로 실행되고요. 일반 def는 블로킹 코드(동기 라이브러리 호출)를 써야 할 때 스레드풀로 넘겨 서버를 안 막히게 해주는 안전망 역할을 해요.
FastAPI는 def와 async def를 섞어 쓰는 것도 문제없이 처리합니다. 각 함수에 가장 적합한 방식을 고르면 되고, 어떤 경우든 FastAPI는 여전히 비동기로 동작하며 빠르게 응답을 처리해요.
기반은 AnyIO¶
FastAPI(와 Starlette)는 AnyIO 기반이라, Python 표준 asyncio와 Trio를 모두 지원합니다. 고급 동시성 패턴이 필요하면 AnyIO를 직접 써서 더 복잡한 코루틴 구조를 만들 수도 있어요.
의존성도 같은 규칙¶
의존성(dependency)은 path operation 함수와 똑같이 FastAPI가 호출하므로 같은 규칙이 적용돼요. 비동기 의존성(async def)을 동기 path operation 안에서 쓰거나, 그 반대로 섞어도 상관없고 FastAPI가 알아서 처리합니다. 다만 우리가 직접 호출하는 일반 유틸리티 함수는 FastAPI가 관여하지 않아서, 동기 함수면 그대로 직접 호출되고 비동기 함수면 코드에서 직접 await해야 해요.
실제 적용 (데이터스케쳐스 관점)¶
FastAPI는 Python 도메인, 특히 AI·자동화 로직과 붙는 API에서 쓰여요.
- LLM 스트리밍 —
async def엔드포인트에서 비동기 클라이언트로 LLM 응답을 스트리밍해 대기 동안 서버가 막히지 않게 해요. - I/O 대기 최적화 — DB·외부 API 호출 같은 I/O를
async def로 처리해 동시 요청 처리량을 높여요. - 동기 라이브러리는 def로 — 어쩔 수 없이 동기 라이브러리를 호출해야 한다면
def로 선언해 스레드풀에 맡겨 서버를 지키죠.
더 알아보기¶
- 공식 문서 (1차): FastAPI Concurrency and async/await
- 인접 챕터: 의존성 주입(Dependencies) · OpenAPI 자동 문서화
- 상위 문서: FastAPI