ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Python] 이벤트 루프는 어떻게 동작하는가 — Pseudo-code로 보는 Asyncio의 내부
    IT 2026. 1. 23. 11:33

    pseudo-code로 보는 asyncio의 내부

    이전 글에서 우리는 이벤트 루프가 “무언가를 실행하는 엔진”이 아니라, 실행 시점을 관리하는 관리자라는 이야기를 했습니다. 그렇다면 이제 이런 질문이 자연스럽게 이어집니다.

    이벤트 루프는 실제로 어떤 순서로, 무엇을 보고 판단할까?

    이번 글에서는 asyncio의 실제 소스코드를 따라가지는 않습니다. 대신 개념을 이해하기에 충분한 수준의 pseudo-code로 이벤트 루프의 동작을 풀어보려 합니다.


    이벤트 루프를 한 문장으로 줄이면

    이벤트 루프는 결국 이것을 무한히 반복합니다.

    • 지금 실행할 수 있는 작업이 있는가?
    • 없다면, 언제까지 기다려야 하는가?
    • 준비된 작업이 생기면 실행한다

    이걸 코드로 상상하면, 놀라울 정도로 단순한 구조가 됩니다.


    가장 단순한 이벤트 루프의 형태

    개념적으로 이벤트 루프는 아래와 비슷합니다.

    while True:
        ready_tasks = get_ready_tasks()
    
        if ready_tasks:
            run_one(ready_tasks)
        else:
            wait_for_io()

    물론 실제 구현은 훨씬 복잡하지만, 핵심 구조는 이 반복문에서 벗어나지 않습니다.

    이제 이 안에서 무슨 일이 일어나는지 하나씩 살펴보겠습니다.


    ready 상태란 무엇인가

    이벤트 루프가 가장 먼저 확인하는 것은 “지금 실행 가능한 작업이 있는가”입니다.

    여기서 말하는 실행 가능이란:

    • await에서 돌아온 코루틴
    • I/O가 완료된 작업
    • 즉시 실행해도 되는 콜백

    을 의미합니다.

    중요한 점은, 이벤트 루프가 작업을 강제로 멈추거나 재개하지 않는다는 것입니다. 오직 준비 상태인지 아닌지만 판단합니다.


    await가 만드는 흐름의 분기

    코루틴이 await를 만나면 무슨 일이 일어날까요?

    await sock.recv()

    이 한 줄은 다음과 같은 의미를 가집니다.

    • 지금은 더 이상 진행할 수 없다
    • I/O가 끝나면 다시 불러달라
    • 그 전까지는 다른 작업을 실행해도 된다

    이 요청을 받은 이벤트 루프는 이 코루틴을 대기 큐로 옮기고, 다음 작업을 살펴봅니다.


    대기(wait)는 잠자는 것이 아니다

    이벤트 루프가 "기다린다"고 할 때, 이는 CPU를 멈추는 것을 의미하지 않습니다.

    • 소켓에 이벤트가 있는지 확인하고
    • 타이머가 만료되었는지 확인하고
    • OS로부터 신호를 기다립니다

    즉, 이벤트 루프의 wait는 운영체제에게 효율적으로 맡기는 대기입니다.


    조금 더 현실적인 pseudo-code

    조금 더 실제에 가까운 형태로 표현하면 다음과 같습니다.

    while True:
        now = current_time()
    
        ready = pop_ready_tasks(now)
        for task in ready:
            task.run()
    
        timeout = time_until_next_event()
        wait_for_io_or_timeout(timeout)

    여기서 중요한 점은:

    • 한 번에 하나의 task만 실행되고
    • task는 스스로 await를 통해 양보하며
    • 이벤트 루프는 그 약속을 믿고 관리만 한다는 것

    입니다.


    그래서 블로킹이 치명적이다

    이 구조를 이해하면, 왜 블로킹 코드가 위험한지도 명확해집니다.

    time.sleep(1)

    이 코드는:

    • 이벤트 루프에게 제어권을 주지 않고
    • 운영체제에게 위임하지도 않으며
    • 그저 현재 스레드를 붙잡아 둡니다

    그 결과, 위의 while 루프 자체가 멈춰버립니다. 다른 작업이 준비되어 있어도, 확인조차 하지 못합니다.


    이벤트 루프는 공정함을 보장하지 않는다

    또 하나 오해하기 쉬운 점은, 이벤트 루프가 모든 작업을 공평하게 처리해줄 것이라는 기대입니다.

    이벤트 루프는:

    • 실행 순서를 보장하지 않고
    • 실행 시간을 제한하지 않으며
    • 양보하지 않는 코루틴을 제어하지 않습니다

    그래서 async 프로그래밍은 문법보다 규율이 중요합니다.


    마무리

    이벤트 루프를 이해하는 가장 좋은 방법은, 이것을 기억하는 것입니다.

    이벤트 루프는 똑똑하지 않다. 다만 매우 성실하다.

    정해진 규칙에 따라 준비된 작업을 실행하고, 기다리고, 다시 실행할 뿐입니다. 이 단순한 구조 위에 async, await, 코루틴, 그리고 비동기 생태계 전체가 쌓여 있습니다.

    이 내부 동작을 한 번 머릿속에 그려두면, async 코드에서 일어나는 대부분의 현상은 더 이상 신비롭게 보이지 않을 것입니다.

Designed by Tistory.