FastAPI의 비동기 프로그래밍 방식
- fastapi는 기본적으로 비동기 프로그래밍을 지원
- 내부적으로 스탈렉과 유비콘같은 ASGI를 사용하기 때문에 비동기 구현이 간단
- asyncio (비동기 프로그래밍을 위한 라이브러리)
- 비동기 i/o, 이벤트 루프, 코루틴
- 네트워크 i/o와 같이 소요시간이 긴 작업들을 효율적으로 처리
- async
- 비동기 함수는 coroutine이라 하며, await을 사용하여 호출
- await은 비동기 실행을 일시 정지하고 코루틴의 실행이 완료될 때까지 대기
- blocking 연산을 대기하는 동안 다른 코루틴이 실행될 수 있게 해주어 효율성 증가
* 비동기와 병렬의 차이점
비동기 : 작업들을 작은 단위로 나누어 번갈아가며 실행, 작업간의 전환을 빠르게 수행하여 여러 작업이 동시에 진행되는 것처럼 보임.
병렬 : 여러개의 CPU 코어 또는 컴퓨터 시스템의 다중 프로세싱 환경을 활용하여 여러 작업을 동시에 처리.
FastAPI의 비동기 프로그래밍
- API 경로 연산 함수에서 사용
- async def로 정의하며 필요 시, await로 비동기 작업 호출 (비동기 함수 내에서 다른 비동기 함수의 실행을 대기)
import asyncio
import random
async def async_func(task_id: int, delay: int):
print(f"Task {task_id}: {delay}초 대기 후 실행")
await asyncio.sleep(delay)
print(f"Task {task_id}: 완료되었습니다.")
async def main():
tasks = []
for i in range(1, 6): # 총 5개의 작업 생성
random_delay = random.randint(1, 10) # 각 작업마다 랜덤 대기 시간 설정
tasks.append(async_func(i, random_delay))
await asyncio.gather(*tasks) # 모든 작업을 동시에 실행
asyncio.run(main())
간단하게 비동기를 어떻게 처리하는지 테스트해보기 위한 코드이다. 동작 방식은 다음과 같다.
- 여러 개의 asnyc_func 작업 생성
- 작업마다 랜덤하게 딜레이 시간을 가짐
- 각 작업을 tasks에 담아 gather로 동시 수행
- await을 사용하여 다른 비동기 함수의 실행을 기다리며 비동기로 처리

실행 결과를 보면 각 작업이 동시에 수행되며, 딜레이 시간이 짧은 작업 순으로 종료되는걸 확인할 수 있다.
(아래 예시는 실제로 동작하지 않는 더미코드임)
from fastapi import FastAPI
import httpx
import asyncio
app = FastAPI()
async def get_remote_data(url):
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()
@app.get("/data")
async def read_data():
external_data = await get_remote_data("https://some-external-api.com/data")
return external_data
- httpx = 비동기로 요청을 처리하는 함수로 request 함수의 비동기 버전
- async = 비동기 함수로 선언
- await = 비동기 함수 내에서 사용되며, 다른 비동기 작업의 완료를 기다리는데 사용
위 코드에서 read_data 함수가 여러번 호출되는 경우 external_data까지 처리해야 하는데, 해당 작업이 오래 소요될 수 있으니 await된 상태에서 다른 read_data가 실행할 수 있음
* (참고)
async로 정의된 함수는 일반적인 함수처럼 호출하면 안되고 await을 사용하거나 async로 선언된 함수 내에서 호출해야 한다.
만약 일반 함수처럼 처리하게 되면 객체가 리턴된다.
또한 일반 함수에서 비동기 함수를 사용할 수 있으며, asyncio의 asyncio run이란 함수로 비동기 함수를 사용하면 된다.
비동기 프로그래밍 정리
- 성능 향상 : 동시에 여러 i/o 작업을 처리할 수 있음
- 리소스 효율성 : 쓰레드 기반의 동시성 모델에 비해 적은 메모리 사용
- 주의점
- blocking 코드 사용 : 비동기 함수 내에서 블로킹 코드 사용 시 전체 성능이 저하될 수 있음
- 에러 핸들링 : 비동기 프로그래밍에서 에러 핸들링이 다소 복잡해질 수 있으며, 적절한 예외 처리가 필요
'Python > FastAPI' 카테고리의 다른 글
| [FastAPI] Pydantic (0) | 2024.11.19 |
|---|---|
| [FastAPI] 파라미터 (작성중) (0) | 2024.11.10 |
| [FastAPI] HTTP 메서드 구현 기본 (0) | 2024.11.10 |
| [FastAPI] FastAPI 기초 문법 (0) | 2024.11.07 |
| [FastAPI] REST와 CRUD (0) | 2024.11.06 |