비동기 프로그래밍
컴퓨터 프로그램에서 특정 코드의 실행이 완료되지 않고 다른 작업을 동시에 진행할 수 있게 하는 것!
asyncio
비동기 프로그래밍을 위한 라이브러리
- 비동기 I/O, 이벤트 루프, 코루틴
- 이벤트 루프 - 코루틴을 실행시키기 위한 여러 방법 중 하나
- 네트워크 I/O와 같이 시간이 많이 소요되는 작업들을 효율적으로 처리해줌
Async/Await 키워드
파이썬에서 비동기 프로그래밍을 구현할 때 사용하는 키워드
→ 위 키워드를 통해 비동기 프로그래밍을 할 수 있다. 이를 실행하기 위해 asyncI/O가 필요하다.
async
- 비동기 함수는 ‘코루틴’이라 하며, await를 사용하여 호출될 수 있음.
- await는 비동기 실행을 “일시 정지”하고 코루틴의 실행이 완료될 때까지 기다린다.
- 블로킹 연상을 대기하는 동안 다른 코루틴이 실행될 수 있게 효율성을 증가시킨다.
FastAPI의 비동기 프로그래밍
- API 경로 연산 함수에서 사용됩니다.
- async def로 정의되며, 필요에 따라 await로 비동기 작업을 호출
비동기 프로그래밍의 장점
- 성능 향상
- 동시에 여러 I/O 바운드 작업을 처리할 수 있다.
- 리소스 효율성
- 쓰레드 기반의 동시성 모델에 비해 적은 메모리를 사용
- 주의사항
- 블로킹 코드의 사용: 비동기 함수 내에서 블로킹 코드(예: 일반 동기 데이터베이스 드라이브)를 사용하면 전체 애플리케이션의 성능 저하가 될 수 있음.
- 에러 핸들링: 비옫기 프로그래밍에서는 에러 핸들링이 다소 복잡해질 수 있으며, 적절한 예외 처리가 필요함.
ASGI
- ASGI - (Asynchronous Server Gateway Interface)
- WSGI (Web Server Gateway Interface)의 한계를 극복하기 위해 계발
- WSGI는 하나의 요청을 처리하는 동안 다른 요청이 대기 상태에 머물게 되는 동기 방식
- 이에 비해 ASGI는 비동기 방식으로 여러 요청을 동시에 처리할 수 있음.
- ASGI의 주요 특징
- 비동기 지원: ASGI는 비동기 요청 처리를 지원하여, 높은 동시성과 성능을 제공
- 웹소켓 지원: 웹소켓과 같은 비동기적 통신 프로토콜을 지원하여, 실시간 양방향 통신이 가능
- 확장성: ASGI는 다양한 이벤트 기반 아키텍처와 함께 사용될 수 있어, 웹 애플리케이션의 확장성을 향상
- 호환성: 다양한 ASGI 호환 웹 프레임워크와 서버가 있어, 선택의 폭이 넓음
FastAPI와 ASGI 서버 정리
FastAPI
- ASGI 인터페이스를 구현하는 Python 웹 프레임 워크
- 비동기 프로그래밍을 통해 높은 성능의 API 쉽게 구축
- 요철을 처리하고 응답을 구성하는 데 사용되는 로직과 도구를 제공
ASGI 서버 (예: Uvicorn)
- FastAPI 애플리케이션과 같은 ASGI 호환 애플리케이션을 호스팅하는 데 사용
- 네트워크 요청을 수신하고, FastAPI 애플리케이션으로 전달 후, 애플리케이션의 응답을 클라이언트에게 반환하는 역할을 한다.
FastAPI를 사용한다는 것은 FastAPI 프레임워크를 사용하여 애플리케이션을 개발한다는 것을 의미
하지만 실제로 웹 요청을 받고 처리하려면 Uvicorn과 같은 ASGI 서버가 필요함.
미들웨어
FastAPI 미들웨어
- 클라이언트로부터의 요청이 처리되기 전과 후에 실행되는 함수
- FastAPI의 모든 요청은 설정된 미들웨어를 거치게 되며, 이를 통해 요청을 로깅하거나, 요청/응답을 수정하거나, 보안 체크를 수행할 수 있다.
미들웨어 추가
- FastAPI에서 미들웨어는 app.middleware(”http”) 데코레이터를 사용해 추가할 수 있다.
예시 코드
- http 요청에 대한 실행 시간 로그를 찍게 하는 미들웨어
from fastapi import FastAPI, Request
import time
from starlette.middleware.base import BaseHTTPMiddleware
app = FastAPI()
class CustomMiddleware(BaseHTTPMiddleware):
async def dispatch(self,request, call_next):
print("Hello It's Me")
response = await call_next(request)
return response
app.add_middleware(CustomMiddleware)
@app.middleware("http")
async def log_requests(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
print(f"Request: {request.method} {request.url} - Completed in {process_time} secs")
return response
@app.get("/")
async def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
라우터
FastAPI 라우팅
- 라우팅은 URL 경로와 해당 경로에 매핑되는 처리 함수 (경로 연산 함수)를 정의하는 과정
- FastAPI에서는 다양한 HTTP 메서드(GET, POST, PUT, DELETE)에 대한 경로 연산을 쉽게 설정할 수 있음
- 라우터는 이걸 처리해주는 객체!
라우터 분리와 재사용성
분리
- 큰 애플리케이션에서는 라우터를 분리하여 기능별로 구분할 수 있음
- 코드의 재사용성 증가!
APIRouter 사용
- APIRouter 클래스를 사용하여 라우터를 별도의 모듈로 분리 가능

미들웨어를 라우터 별로 따로 지정은 불가능! 미들웨어는 일반적으로 애플리케이션 전체에 적용되기 때문
- 라우터별로 특정 미들웨어의 동작을 구현하고 싶은 경우는 Depend라는 것을 사용
- 라우터 그룹을 특정 그룹에 대해서만 사용자 인증을 요구하고 싶다면 디펜드로 구현 가능