본문 바로가기

카테고리 없음

Python : Event_loop - 동기작업을 비동기로 처리하기

  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())

 

  1. 블로킹 함수 정의: blocking_task는 time.sleep()을 통해 특정 시간 동안 대기하는 함수로, CPU 바운드 또는 블로킹 작업의 예입니다.
  2. 스레드 풀 설정: ThreadPoolExecutor를 사용해 스레드 풀을 정의하고, 스레드 풀에 작업을 제출하여 각기 다른 스레드에서 블로킹 작업이 실행되도록 합니다.
  3. run_in_executor 사용: loop.run_in_executor(executor, blocking_task, duration)로 블로킹 함수를 비동기적으로 실행합니다. 여기서 duration은 블로킹 함수에 전달할 인자입니다.
  4. 결과 대기: asyncio.gather로 모든 Task가 완료될 때까지 기다린 후, 결과를 출력합니다.

run_in_executor를 사용할 때 주의사항

  • run_in_executor는 CPU 바운드 또는 블로킹 I/O 작업을 효율적으로 처리할 수 있지만, 모든 작업에 대해 run_in_executor를 남용하는 것은 성능 저하를 일으킬 수 있습니다.
  • ThreadPoolExecutor를 사용하면 스레드 기반으로 병렬 처리가 이루어지고, ProcessPoolExecutor를 사용하면 프로세스 기반 병렬 처리가 수행됩니다.