Event_loop의 run_in_executor는 CPU 바운드 작업 또는 비동기 지원이 되지 않는 작업을 비동기적으로 처리하기 위해 asyncio에서 제공하는 메서드입니다. 비동기 함수로 전환할 수 없는 함수(예: 블로킹 I/O 작업, 복잡한 계산 작업 등)를 별도의 스레드나 프로세스에서 실행하고, 이벤트 루프는 다른 비동기 작업을 계속 실행할 수 있게 합니다.
run_in_executor의 기본 사용법
run_in_executor는 다음과 같이 사용할 수 있습니다:
await loop.run_in_executor(executor, blocking_func, *args)
- loop: 이벤트 루프 객체입니다.
- executor: concurrent.futures.ThreadPoolExecutor 또는 ProcessPoolExecutor로 정의한 실행자입니다. None으로 설정하면 기본적으로 스레드 풀이 사용됩니다.
- blocking_func: 실행할 블로킹 함수입니다.
- args: 블로킹 함수에 전달할 인수입니다.
예제: 블로킹 함수와 run_in_executor
아래 예제는 CPU 바운드 작업(예: 긴 시간 동안의 계산)을 run_in_executor를 사용해 비동기적으로 실행하는 방법을 보여줍니다.
import asyncio
from concurrent.futures import ThreadPoolExecutor
import time
# 블로킹 함수 정의 (예: CPU 바운드 작업)
def blocking_task(duration):
print(f"Blocking task started for {duration} seconds")
time.sleep(duration)
print("Blocking task completed")
return f"Task finished in {duration} seconds"
async def main():
loop = asyncio.get_running_loop()
# 스레드 풀 실행자 정의
with ThreadPoolExecutor() as executor:
print("Submitting blocking tasks to executor")
# run_in_executor를 사용해 블로킹 작업을 비동기적으로 실행
task1 = loop.run_in_executor(executor, blocking_task, 3)
task2 = loop.run_in_executor(executor, blocking_task, 5)
# 결과 대기
results = await asyncio.gather(task1, task2)
print("Results:", results)
# 이벤트 루프 실행
asyncio.run(main())
- 블로킹 함수 정의: blocking_task는 time.sleep()을 통해 특정 시간 동안 대기하는 함수로, CPU 바운드 또는 블로킹 작업의 예입니다.
- 스레드 풀 설정: ThreadPoolExecutor를 사용해 스레드 풀을 정의하고, 스레드 풀에 작업을 제출하여 각기 다른 스레드에서 블로킹 작업이 실행되도록 합니다.
- run_in_executor 사용: loop.run_in_executor(executor, blocking_task, duration)로 블로킹 함수를 비동기적으로 실행합니다. 여기서 duration은 블로킹 함수에 전달할 인자입니다.
- 결과 대기: asyncio.gather로 모든 Task가 완료될 때까지 기다린 후, 결과를 출력합니다.
run_in_executor를 사용할 때 주의사항
- run_in_executor는 CPU 바운드 또는 블로킹 I/O 작업을 효율적으로 처리할 수 있지만, 모든 작업에 대해 run_in_executor를 남용하는 것은 성능 저하를 일으킬 수 있습니다.
- ThreadPoolExecutor를 사용하면 스레드 기반으로 병렬 처리가 이루어지고, ProcessPoolExecutor를 사용하면 프로세스 기반 병렬 처리가 수행됩니다.