-
[Python] 서브루틴과 코루틴 — 흐름을 누가 쥐고 있는가IT 2026. 1. 23. 11:12
프로그램을 작성할 때 우리는 끊임없이 함수를 호출합니다. 너무 자연스럽게 쓰다 보니, 보통은 이런 질문을 하지 않습니다.
“함수를 호출하면, 흐름은 누가 가지고 있을까?”
서브루틴과 코루틴의 차이는 문법의 차이가 아니라, 바로 이 제어 흐름(control flow) 에 대한 관점 차이에서 시작됩니다. 이 글에서는 두 개념을 비동기 문법이나 구현 세부가 아니라, 프로그램이 어떻게 실행을 이어가는가라는 큰 그림에서 풀어보려 합니다.
우리가 익숙한 함수는 서브루틴이다
우리가 일반적으로 사용하는 함수는 모두 서브루틴(subroutine) 입니다.
def add(a, b): return a + b result = add(1, 2)이 코드에서 흐름은 명확합니다.
- add를 호출하면
- 호출한 쪽의 실행은 멈추고
- 함수가 끝날 때까지 기다린 뒤
- 결과를 받아 다시 이어서 실행합니다
즉, 흐름의 주도권은 항상 호출자에게 있습니다. 서브루틴은 이름 그대로 “하위 작업”입니다.
서브루틴의 한계
서브루틴 구조는 단순하고 이해하기 쉽지만, 한 가지 제약이 있습니다.
- 한 번 호출되면
- 끝날 때까지
- 중간에 흐름을 돌려줄 수 없다
이 구조는 계산에는 잘 맞지만, 다음과 같은 상황에서는 답답해집니다.
- 중간 결과를 여러 번 내놓고 싶을 때
- 상태를 유지한 채로 여러 번 재개하고 싶을 때
- 협력적으로 작업을 나누고 싶을 때
이 지점에서 코루틴이 등장합니다.
코루틴은 흐름을 주고받는다
코루틴(coroutine)은 이름 그대로 함께 실행되는 루틴입니다.
핵심 차이는 이것입니다.
코루틴은 실행을 멈췄다가, 다시 이어서 실행할 수 있다
즉, 코루틴은 실행 상태를 기억한 채로 흐름을 호출자에게 양보(yield) 할 수 있습니다.
파이썬에서 코루틴을 가장 단순하게 보면
파이썬에서 코루틴의 가장 직관적인 형태는 yield를 사용하는 함수입니다.
def counter(): yield 1 yield 2 yield 3이 함수는 한 번에 끝까지 실행되지 않습니다.
c = counter() next(c) # 1 next(c) # 2 next(c) # 3여기서 중요한 점은 counter가 자기 상태를 기억하고 있다는 것입니다. 이것이 서브루틴과의 결정적인 차이입니다.
흐름의 방향이 바뀐다
서브루틴에서는 항상 이렇게 흐름이 움직입니다.
caller → callee → caller하지만 코루틴에서는 흐름이 이렇게 오갑니다.
caller ⇄ coroutine호출자와 코루틴은 상하 관계가 아니라, 협력 관계에 가깝습니다.
왜 코루틴이 필요해졌을까
코루틴은 단순한 트릭이 아니라, 현실적인 문제에서 등장했습니다.
- I/O 대기
- 이벤트 처리
- 비동기 작업
이런 작업들은 “끝날 때까지 기다리는 서브루틴”보다, 잠깐 실행하고 양보하는 구조가 훨씬 효율적입니다.
async / await는 코루틴의 진화형이다
파이썬의 async / await 문법은 완전히 새로운 개념이 아닙니다. 기존의 코루틴 개념을 언어 차원에서 안전하게 정리한 형태에 가깝습니다.
async def fetch(): await something()여기서도 핵심은 같습니다.
- 실행을 멈추고
- 다른 작업에게 흐름을 넘기고
- 다시 돌아와 이어서 실행
서브루틴 vs 코루틴 한 문장 정리
- 서브루틴 → 호출되면 끝까지 실행한다
- 코루틴 → 실행하다가 흐름을 돌려준다
차이는 작아 보이지만, 이 차이가 프로그램 구조를 완전히 바꿉니다.
마무리하며
코루틴과 서브루틴의 차이는 비동기냐 아니냐의 문제가 아닙니다.
그보다는 이렇게 정리할 수 있습니다.
“누가 실행 흐름을 쥐고 있는가?”
이 질문에 대한 답이 달라지는 순간, 함수는 더 이상 단순한 호출 대상이 아니라, 협력하는 실행 단위가 됩니다. 그리고 그 지점이 바로 코루틴의 출발점입니다.
'IT' 카테고리의 다른 글
[Python] Async 핵심 개념 3부작 — 이벤트 루프, 동시성, 블로킹 (1) 2026.01.23 [Python] GIL — 파이썬은 왜 멀티코어를 막아놓았을까 (0) 2026.01.23 [Python] abc 모듈과 추상 메서드 — 규칙을 코드로 표현하는 방법 (0) 2026.01.23 [Python] 커링(currying)을 이해한다는 것 (0) 2026.01.23 [DB] DB에서 인덱스란 무엇인가 — 인덱스 스캔과 시퀀스 스캔 (1) 2026.01.22