[Python] Coroutine 기본
Python에서 코루틴(Coroutine)은 비동기 프로그래밍을 가능하게 하는 중요한 개념입니다. 이번 글에서는 코루틴이 무엇인지, 어떻게 정의하고 호출하는지, 일반 함수와의 차이점, 그리고 CPU-bound 작업이 길어질 때 asyncio.to_thread()
를 활용하는 방법까지 자세히 알아보겠습니다.
1. 코루틴이란?
코루틴은 함수의 실행을 중간에 일시 중지하고, 나중에 다시 그 지점부터 실행을 재개할 수 있는 특별한 함수입니다. 일반 함수와 달리 비동기 작업을 효율적으로 처리할 수 있게 해줍니다. Python에서는 async def
키워드를 사용해 코루틴을 정의합니다.
코루틴은 주로 I/O 바운드 작업(네트워크 요청, 파일 입출력 등)에서 CPU를 낭비하지 않고 다른 작업을 처리할 수 있게 해줍니다.
2. 코루틴 정의와 호출 방법
코루틴 정의
import asyncio
async def my_coroutine():
print("코루틴 시작")
await asyncio.sleep(1) # 1초 대기 (비동기)
print("코루틴 끝")
async def
로 코루틴 함수를 정의합니다.await
키워드는 다른 코루틴이나 비동기 작업의 완료를 기다릴 때 사용합니다.
코루틴 호출
코루틴은 일반 함수처럼 호출해도 바로 실행되지 않고, 코루틴 객체를 반환합니다. 실행하려면 이벤트 루프에서 실행해야 합니다.
async def main():
await my_coroutine()
asyncio.run(main())
asyncio.run()
함수는 이벤트 루프를 생성하고, 코루틴을 실행합니다.await
를 통해 코루틴이 완료될 때까지 기다립니다.
3. 일반 함수와 코루틴의 차이점
구분 | 일반 함수 | 코루틴 함수 |
---|---|---|
정의 방식 | def |
async def |
호출 결과 | 실행 결과 반환 | 코루틴 객체 반환 |
실행 방식 | 호출 즉시 실행 | 이벤트 루프에서 실행 필요 |
중단 가능 여부 | 중간에 실행 중단 불가 | await 로 실행 중단 가능 |
주 용도 | 동기 작업 처리 | 비동기 작업 처리 |
코루틴은 비동기 작업을 효율적으로 처리하기 위해 설계된 함수입니다. 일반 함수는 호출 즉시 실행되지만, 코루틴은 이벤트 루프에서 실행되어 다른 작업과 병렬로 처리할 수 있습니다.
4. CPU-bound 작업과 asyncio.to_thread()
asyncio
는 본래 I/O 바운드 작업에 최적화되어 있습니다. 하지만 CPU를 많이 사용하는 작업(CPU-bound)은 코루틴만으로는 효율적으로 처리하기 어렵습니다. 이럴 때 asyncio.to_thread()
를 사용하여 CPU-bound 작업을 별도의 스레드에서 실행할 수 있습니다.
CPU-bound 작업 예시
import asyncio
import time
def cpu_bound_task(x):
print(f"CPU 작업 시작: {x}")
time.sleep(3) # CPU 작업 시뮬레이션 (블로킹)
print(f"CPU 작업 끝: {x}")
return x * x
async def main():
print("비동기 작업 시작")
result = await asyncio.to_thread(cpu_bound_task, 5)
print(f"결과: {result}")
asyncio.run(main())
cpu_bound_task
는 블로킹 작업입니다.asyncio.to_thread()
는 이 작업을 별도의 스레드에서 실행해 이벤트 루프를 막지 않습니다.- 여러 CPU-bound 작업이 있을 때도 비동기적으로 처리할 수 있습니다.
5. 마무리
- 코루틴은
async def
로 정의하며,await
로 비동기 작업을 기다립니다. - 일반 함수와 달리 코루틴은 이벤트 루프에서 실행됩니다.
- CPU-bound 작업은
asyncio.to_thread()
로 별도 스레드에서 실행해 비동기 환경을 유지할 수 있습니다.
TL;DR
- 코루틴은
async def
로 정의하는 비동기 함수입니다. await
로 중간에 실행을 멈추고 다른 작업을 처리할 수 있습니다.- CPU-bound 작업은
asyncio.to_thread()
로 별도 스레드에서 실행해 효율적 처리 가능.
댓글남기기