최근 회사에서 코딩을 하다가 문제없이 작성한 코드에서 Coroutine 에러가 났었습니다.
처음보는 에러였는데 내용을 살펴보니 파이썬 비동기 함수를 제대로 사용하지 못했던게 이유였습니다.
파이썬 비동기 라이브러리인 asyncio에 대해 알아보기 전에
동기와 비동기 개념에 대해서 알아보겠습니다.
동기와 비동기
동기(synchronous)처리는 특정 작업이 끝나면 다음 작업을 처리하는 순차처리 방식이고 비동기(asynchronous)처리는 여러 작업을 처리하도록 예약한 뒤 작업이 끝나면 결과를 받는 방식입니다.
비동기의 장점은 Request, I/O와 같이 딜레이가 발생하는 작업에서 뛰어난 효과를 보입니다. 즉 서버에 요청하거나 데이터를 읽는 등에 대한 작업에서 유리합니다. 대기 시간이 발생하는 상황에서의 시간을 다른 작업을 수행하는데 활용함으로써 전체적인 소요 시간이 감소하는 것입니다.
def test():
print('1')
print('2')
def main():
test()
main()
동기 함수는 위와 같이 일반적으로 함수를 선언해주면 되는데 위 코드는 main 함수가 test를 실행하고 1과 2가 출력된 후 종료됩니다. 호출된 main함수는 test 함수가 종료될 때까지 기다리게 됩니다.
현재 코드는 짧고 처리해야 하는 부분이 적어 시간적으로 크게 차이가 없을지라도 엄청나게 많은 데이터를 출력해야하는 상황이라면 test함수가 종료되기까지 기다리는 것은 비효율적이며 성능을 저하시키는 일이 될 수 있습니다. 이때 필요한 것이 비동기 처리입니다.
import asyncio
async def f():
return 30
async def main():
ret = f()
# 코루틴 객체 생성되었지만 await하고 있지 않기 때문에
# 아무런 일도 발생하지 않는다.
ret = await f()
# ret: 30
# 실제 코루틴이 실행되고 값을 반환한다.
비동기 함수는 동기함수와는 다르게 호출된 함수의 실행이 다 끝나지 않았어도 호출한 함수에게 return 합니다. 이후에 작업이 끝났을 때에야 호출한 함수에게 작업이 끝났다고 통보해줍니다. 파이썬에서는 asyncio 라이브러리를 지원하고 있으며 함수 앞에 anync를 붙여줌으로써 코루틴을 선언할 수 있습니다.
제가 재직중인 회사에서는 해외 렌터카 업체들과 API 통신을 통해 데이터를 받아오고 데이터를 가공해 정보를 제공하고 있는데요, 데이터 양이 많기 때문에 비동기처리를 통해 빠른처리를 하고자 합니다.
@classmethod
async def get_cancellation_policy_list(cls, session: AsyncSession, 지점코드: str) -> Self:
stmt = select(cls).where(cls.지점코드 == 지점코드)
return await session.scalar(result)
위 코드처럼 DB에 저장된 취소정책에 대한 컬럼값을 가져오기 위해 비동기로 선언해 지점코드로 DB테이블에서 지점코드에 해당하는 값을 불러오는 함수를 만들었었습니다.
temp = get_cancellation_policy_list(session, office.code)
그리고 temp값에 실행한 함수값을 담도록 해줬었는데요 coroutine 'get_cancellation_policy_list' was never awaited 라는 에러를 받았습니다.
temp = await get_cancellation_policy_list(session, office.code)
이 부분이 제가 비동기를 제대로 활용하지 못했던 부분입니다. 비동기 함수는 동기함수와 다르게 작업완료를 보장해주지 않습니다. 동기함수는 순차적으로 처리되기 때문에 다음 함수가 실행된다는 것은 이전 작업이 완료되었다는 보장이 가능하지만 비동기 함수에서는 보장할 길이 없는 것이죠. 해당 에러는 실행 함수 앞에 await을 붙여줌으로써 간단하게 해결 가능했습니다.
하지만 비동기가 무조건적으로 빠른 처리를 해주는 것은 아니다
서두에 Request, I/O 프로세스와 같이 딜레이가 발생하는 작업에서는 비동기가 뛰어난 효과를 보인다고 했었는데요, CPU bound 작업의 경우에는 오히려 비동기로 처리했을 때 더 많은 시간이 소요된다고 합니다. 따라서 파이썬에서 비동기 작업을 할 때에는 사용목적에 따라 적절하게 선택하는 것이 중요할 것 같습니다.
출처:
https://denev6.tistory.com/entry/python-asyncio
https://dojang.io/mod/page/view.php?id=2469
https://ffoorreeuunn.tistory.com/462
'Python > FastAPI' 카테고리의 다른 글
FastAPI에서 MySQL 연결 (0) | 2023.12.24 |
---|---|
Dependency와 FastAPI에서의 Dependency Injection (2) | 2023.12.22 |
FastAPI에서 JWT 로그인 기능 구현하기(회고) (0) | 2023.12.16 |
FastAPI localhost port 변경 (0) | 2023.11.01 |