[WAFFLE] 04-5 Event Loop

2 minute read

Published:

In this post, concepts of event loop will be introduced.

이벤트 루프의 정의

  • 이벤트 루프는 비동기 작업을 스케줄링하고 실행하는 중심 역할을 하는 루프 구조입니다.
  • 즉, 실행할 작업(태스크, 이벤트, 콜백 등)을 계속 감시하며 준비된 작업이 있으면 처리합니다.

이벤트 루프의 주요 원리

  1. 작업 등록
    • 비동기 작업(코루틴, 콜백 등)을 이벤트 루프에 등록합니다.
    • 작업이 준비되면 이벤트 루프가 이를 실행합니다.
  2. 중단점(await)에서 멈춤
    • 비동기 작업은 await 키워드나 I/O 대기 시점에서 실행을 일시 중단합니다.
    • 이때 이벤트 루프는 대기하지 않고 다른 작업을 실행합니다.
  3. 작업 완료 후 재개
    • 대기 중인 작업이 완료되면, 이벤트 루프가 해당 작업의 실행을 재개합니다.

이벤트 루프의 동작 과정

이벤트 루프는 아래 단계를 반복적으로 실행합니다.

  1. 작업 큐(Task Queue)에 작업 등록
    • 비동기 작업, 콜백 함수, 타이머 등의 작업이 작업 큐에 들어갑니다.
  2. 준비된 작업 실행
    • 작업 큐에서 준비된 작업을 하나 꺼내 실행합니다.
  3. 중단점에서 대기
    • 작업 실행 중 await이나 I/O 작업이 발생하면, 해당 작업은 중단되고 다시 큐로 반환됩니다.
  4. 다른 작업 처리
    • 이벤트 루프는 중단된 작업 대신 다른 준비된 작업을 실행합니다.
  5. 작업 완료 후 재개
    • 중단된 작업이 완료되면, 해당 작업은 큐로 돌아와 재개됩니다.

이벤트 루프의 실제 동작 예시

다음은 Python의 asyncio를 사용한 간단한 이벤트 루프 예제입니다.

import asyncio

async def task1():
    print("Task 1 시작")
    await asyncio.sleep(2)  # 중단점: 2초 대기
    print("Task 1 완료")

async def task2():
    print("Task 2 시작")
    await asyncio.sleep(1)  # 중단점: 1초 대기
    print("Task 2 완료")

async def main():
    # 이벤트 루프에 작업 등록
    await asyncio.gather(task1(), task2())  # 두 작업을 동시에 실행

asyncio.run(main())
Task 1 시작
Task 2 시작
Task 2 완료
Task 1 완료
  1. task1()과 task2()가 이벤트 루프에 등록됩니다.
  2. 이벤트 루프가 task1()을 실행하고, await asyncio.sleep(2)에서 중단합니다.
  3. 중단된 사이에, 이벤트 루프가 task2()를 실행하고, await asyncio.sleep(1)에서 중단합니다.
  4. 1초 후, task2()가 완료되며 출력.
  5. 2초 후, task1()이 완료되며 출력.

이벤트 루프의 주요 구성 요소

  1. 작업 큐 (Task Queue)
    • 실행 대기 중인 비동기 작업이 저장됩니다.
  2. 대기 목록 (Waiting List)
    • await 상태에서 대기 중인 작업이 저장됩니다.
    • 작업이 완료되면 다시 작업 큐로 이동합니다.
  3. 콜백 큐 (Callback Queue) -완료된 작업의 결과를 처리하기 위한 콜백 함수가 저장됩니다.

왜 이벤트 루프가 중요한가?

  • 효율적인 리소스 사용
    • 이벤트 루프는 단일 스레드로 동시성을 지원합니다.
    • 스레드나 프로세스를 추가 생성하지 않아도, 여러 작업을 동시에 처리하는 것처럼 보이게 합니다.
  • I/O 대기 시간 활용
    • I/O 작업 중 발생하는 대기 시간을 활용하여 다른 작업을 처리합니다.
    • 이를 통해 높은 처리량을 달성할 수 있습니다.

이벤트 루프의 실제 사례

웹 서버에서의 활용 (FastAPI)

  • FastAPI와 같은 비동기 웹 프레임워크는 이벤트 루프를 기반으로 작동합니다.
    • 클라이언트 요청이 들어오면 이벤트 루프가 요청을 작업으로 등록합니다.
    • 작업이 처리되는 동안 I/O 대기 상태가 발생하면, 이벤트 루프는 다른 요청을 처리합니다.
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    await asyncio.sleep(1)  # 비동기 대기
    return {"message": "Hello, World!"}

Leave a Comment