1. 파이썬의 비동기 프로그래밍
비동기 작업은 보통 async/await 키워드를 사용하여 정의하는데, async를 이용해 비동기함수(코루틴) 정의하고, await를 이용해 비동기 함수 내에서 시간이 오래걸리는 작업을 수행할 때 사용한다. 이를테면 대용량 파일을 읽고 쓰는 작업, db쿼리, 많을 수의 클라이언트를 처리해야 하는 웹서버에서 주로 사용한다.
from pydantic import BaseModel
class UserSchema(BaseModel)
id: int
name: str
class Config:
orm_mode = True
async def get_user_by_id(user_id: int):
async with AsyncSessionLocal() as session:
query = select(User).where(User.id == user_id)
result = await session.execute(query)
user = result.scalar_one()
return UserSchema.from_orm(user)
- with 키워드는 리소스를 획득하고 사용 후 반납할 때 주로 사용한다. db세션을 이용하는 경우 다른 프로세스를 위해 반납해야 한다. try/except/finally를 통해 비슷한 구현이 가능하지만 이 방법 역시 예외가 발생하는 케이스와 조건을 만족하는 케이스에 대해 리소스를 정리하는 코드가 중복으로 작성된다.
- 파이썬의 컨텍스트 매니저는 with문법을 통해 with절 내에서만 리소스를 액세스 가능하게 하고 블록을 나가면 어떤 이유든 간에 리소스를 해제하게 된다. 'with 함수명 as 변수'의 형태로 사용하며 중첩이 가능한 장점이 있다. 중첩된 함수중 하나에서 문제가 발생하면 가장 하위 블럭에서부터 파일을 순차적으로 닫고, 안전하게 리소스를 회수할 수 있다. 로직의 전후관계를 추적할 필요가 없으므로 코드를 간결하게 한다.
ContextManager
이것은 with 구문에 쓰일 수 있는 객체의 타입이며, Context Manager 프로토콜을 준수한다. 또한 다음의 메소드를 정의하고 있는 것으로 간주하는데,
1. __enter__(self) : with 문에 진입하는 시점에 자동 호출
2. __exit__(self, type, value, traceback): with문에 끝나기 직전에 자동 호출
위와 같은 개념의 with 키워드를 비동기로 사용하려면 async만 붙이면 된다. 그리고 위의 함수를 아래와 같이 실행할 수 있다. 그리고 FastAPI는 Starlette 위에서 동작하고, Starlette는 ASGI(Asynchronous Server Gateway Interface) 스펙을 따른다. 이 구조 덕분에 Python의 asyncio 이벤트 루프를 자동으로 사용하게 되고, async def, await 문법만 써도 비동기 처리가 자연스럽게 되는 것이다.
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/users/{user_id}", response_model=UserSchema)
async def read_user(user_id: int):
user = await get_user_by_id(user_id)
if user is None:
raise HTTPException(status_code=404, detail="User not Found")
return user
- WSCI(Web Server Gateway Interfase)
파이썬 웹 애플리케이션과 엡 서버 간의 표준 인터페이스로 동기식처리를 기반으로 HTTP 프로토콜만 지원하여 WebSocket 같은 새로운 프로토콜을 지원할 수 없고 블로킹 I/O 모델로 한번에 하나의 요청만 처리한다.
- ASGI(Asynchronout Server Gateway Interface)
WSGI의 후속 표준으로 비동기 웹 애플리케이션을 지원하기 위해 개발되었고 Starlette 프레임워크도 이것을 기반으로 동작한다. Uvicorn이 대표적이고 비동기식 처리, HTTP/WebSocket, HTTP/2 등 다중프로토콜을 지원하여 논블로킹 I/O 모델이다.
uvicorn을 사용하는 이유
FastAPI는 웹 프레임워크로 동작하기 위해선 ASGI 애플리케이션 객체(main.py의 app = FastAPI)를 제공한다. 하지만 이 앱은 단독으로 HTTP 요청을 받을 수 없어 실제로 외부와 연결해주는 역할을 한다. 사용할 수 있는 옵션은 다음과 같다.
- --host : 바인딩할 호스트(보통 0.0.0.0이나 localhost)
- --port : 바인딩할 포트(기본: 8000)
- --reload : 코드 수정시 자동 재시작
- --workers : 워커 수(gunicorn 같은 툴로 연결: 멀티프로세싱)
- --log-level : 로그 레벨 설정(info, debud 등)
2. FastAPI에서 Redis 사용하기
1. 레디스란
- 고성능 인메모리 데이터베이스로 키-값 데이터구조를 지원, 데이터가 메모리에 저장되어 매우 빠른 읽기/쓰기 속도를 제공한다.
- Lists, Sets, Hashes, Streams 등의 다양한 데이터 구조를 지원한다.
- 캐싱, 세션저장소, 실시간분석, 메시지 큐 등이 필요할 때 사용
import redis
import time
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
def blocking_redis_operation():
print("Start blocking call")
value = r.get("some_key") # 여기서 Redis 서버로 I/O 요청을 보냄
print("Got value:", value)
def do_other_work():
for i in range(3):
print("Doing something else...", i)
time.sleep(1)
blocking_redis_operation()
do_other_work()
# Start blocking call
# Got value: None
# Doing something else... 0
# Doing something else... 1
# Doing something else... 2
순서대로 blocking_redis_operation()의 print문까지 모두 동작한 후 do_other_work가 동작한다. 반면 비동기 redis 코드는 다음과 같다. 반면 아래의 비동기 redis 코드는 non_blocking_redis_operation()이 동작하는 중에 do_other_work()가 끼어들어 print문의 순서가 바뀌었다. 그리고 내가 참고한 블로그의 내용에선 aioredis가 python의 비동기 redis 라이브러리라고 하는데, 찾아보니 aioredis는 redis-py에 통합되었고 아래처럼 redis.asyncio로 사용하는 듯하다.
import asyncio
import redis.asyncio as redis # 비동기 Redis 클라이언트
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
async def non_blocking_redis_operation():
print("Start async Redis call")
value = await r.get("some_key") # await로 Redis 응답을 기다림 (다른 일 가능)
print("Got value:", value)
async def do_other_work():
for i in range(3):
print("Doing something else...", i)
await asyncio.sleep(1)
async def main():
await asyncio.gather(
non_blocking_redis_operation(),
do_other_work()
)
asyncio.run(main())
# Start async Redis call
# Doing something else... 0
# Got value: None
# Doing something else... 1
# Doing something else... 2
'내용 복습 > python' 카테고리의 다른 글
FastAPI 공부 3일차 (0) | 2025.05.18 |
---|---|
FastAPI 공부 2일차 (0) | 2025.04.26 |
FastAPI 공부내용 1일차 (0) | 2025.04.25 |
데이터 공부 with 파이썬 2일차 (1) | 2025.02.08 |
데이터분석 with 파이썬 1 (0) | 2025.02.06 |