
코루틴(Coroutine)이란?
실행의 지연과 재개를 허용함으로써,
비선점적 멀티태스킹을 위한 서브 루틴을 일반화한 컴퓨터 프로그램 구성요소.
위키피디아에서는 코루틴을 위와 같이 정의한다.
코루틴은 Co(함께, 서로) + routine(규칙적인 일의 순서, 작업의 집합) 2개의 단어가 합쳐진 용어로, 함께 동작하며 규칙이 있는 일의 순서를 뜻한다.
코루틴 개념은 스레드 개념이 나타나기도 전인 1958년에 존재했으며 어셈블리 프로그램에서부터 적용되었던 개념이다.
하지만 당시에 코루틴은 거의 사용되지 않았고, 고대 기술처럼 존재했다.
오늘날 사용자 요청이 기하급수적으로 늘어나게 되면서, 코루틴은 높은 성능과 동시성을 요구하는 분야에서 다시금 각광받기 시작했으며 C#, Javascript, Python, Go와 같은 고급 프로그래밍 언어에서도 지원하고 있다.
먼저 파이썬으로 구현한 간단한 함수를 이용해 코루틴을 이해해보자.
// 일반함수
def func();
print("a")
print("b")
print("c")
def foo():
func();
위 foo 함수가 func 함수를 호출하여 실행이 완료되면 다음 값이 출력된다.
// 실행 결과
a
b
c
코루틴은 이와 어떻게 다를까?
코루틴에는 스레드와 매우 유사한 기능인 <일시 중지>와 <재개> 기능이 있다.
// 코루틴의 기능
def func();
print("a")
일시 중지 및 반환
print("b")
일시 중지 및 반환
print("c")
코루틴은 자신의 실행 상태 정보를 저장하여 코루틴이 반환된 후에도 계속 호출이 가능하며, 마지막으로 일시 중지된 지점에서 다시 이어서 실행이 가능하다.
일반적으로 이 <일시 중지> 주문을 프로그래밍 언어에서는 yield 예약어로 사용한다.
다음은 코루틴 함수를 사용해보는 예제이다.
// 코루틴 함수
def func();
print("a")
yield
print("b")
// 코루틴 사용
def A();
co = func() # 코루틴 획득
next(co) # 코루틴 호출
print("in function A") # 작업 실행
next(co) # 코루틴 재호출
획득한 코루틴을 next로 호출하면, 코루틴 함수 안에서 yield를 만나 중지되어 함수 A로 돌아온다. 이 후 코루틴을 재호출하면 일시 중지되었던 지점에서 재개된다.
// 결과
a
in function A
b
일반 함수와 코루틴의 호출 방식을 눈으로 보면, 실행 흐름을 알 수 있다.

루틴과 서브루틴
프로그램은 여러 루틴의 조합으로 진행되는데, 메인 루틴과 서브 루틴이 있다.
- 메인 루틴: 프로그램 전체의 개괄적인 동작으로 main 함수에 의해 수행되는 흐름
- 서브 루틴: 반복적인 기능을 모은 동작으로 main 함수 내에서 실행되는 개별 함수의 흐름
위 일반 함수의 흐름이 서브 루틴의 동작과 같다.
서브 루틴은 메모리에 기능을 모아 놓고, 호출 시 저장된 메모리로 이동한 뒤 실행 후 반환문(return)을 통해 원래의 호출 위치로 돌아온다.
단일 진입 지점에서 시작하고, 단일 반환 지점에서 종료된다.

코루틴은 협동 루틴으로, 루틴과 서브 루틴은 서로 비대칭적인 관계이지만 코루틴은 서로가 서로를 호출하기에 완전히 대칭적인 관계이다. 코루틴들에서는 무엇이 무엇의 서브루틴인지를 구분하는 것이 불가능하다. (서로가 서로를 서브 루틴으로 생각함)
코루틴은 진입과 반환 지점이 여러개로, 진입 후 반환문이 없더라도 임의의 지점에서 동작을 중단하고 해당 지점에서 실행을 재개한다.
이는 내부적으로 Continuation Passing Style(CPS, 연속 전달 방식)과 State machine을 이용하여 동작한다.

코루틴이 자신이 일시 중지될 때의 실행 상태를 저장했다가 그 상태에서 다시 실행을 시작하는 것은 마치 운영 체제가 스레드를 스케줄링하는 것과 매우 유사하다.
스레드A를 일시 중지하고 실행 상태를 저장해두었다가 스레드B의 스케줄링을 진행하고, 다시 일시 중지되었던 스레드A가 CPU의 리소스를 할당받으면 스레드A는 해당 지점에서 이어서 실행된다.
운영체제와 다른 점은 컴퓨터 시스템이 타이머 인터럽트(timer interrupt)를 생성하여 자동으로 일시 중지 여부를 결정하지만, user mode에서는 이러한 작동 방식이 없기 때문에 코루틴에서 yield, suspend(kotlin)과 같은 예약어를 사용하여 명시적으로 위치를 지정해야 한다는 것이다. 코루틴을 통해 프로그래머는 운영 체제와 유사한 역할을 할 수 있다.
[유의할 점]
운영 체제는 코루틴 생성에 대해 알지 못한다.
코루틴은 온전히 사용자 상태 내에서 구현되었기 때문에 코루틴은 사용자 상태 스레드로 해석된다.
코루틴은 어떻게 구현될까?
코루틴의 구현은 스레드의 구현과 본질적으로 유사하다.
코루틴이 일시 중지될 때는 상태 정보를 반드시 기록해야 하는데, 이 상태 정보에는 (1) CPU의 레지스터 정보, (2) 함수 실행 시 상태 정보가 포함된다.
이 정보는 주로 함수의 스택 프레임에 저장되는데,
프로세스 주소 공간의 스택 영역은 스레드를 위한 공간이므로, 코루틴의 스택 프레임 정보는 힙 영역의 메모리에 저장된다.

실행 흐름은 여러 개지만 스레드는 단 하나만 생성된다.
이론적으로 메모리 공간이 충분하다면 코루틴은 무한 생성 가능하며, 코루틴 스케줄링은 전적으로 사용자 상태에서 일어나므로 운영 체제 개입이 필요 없고, 가볍고 효율성이 높다.
비선점적 멀티태스킹
- 비선점형: task가 스케줄러로부터 CPU 사용권을 할당받았을 때 스케줄러가 강제로 CPU 사용권을 뺏을 수 없다.
- 선점형: task가 CPU를 사용하고 있더라도 이 사용권을 뺏어서 task를 중단시킬 수 있다.
코루틴은 비선점형 멀티태스킹이며, 스레드는 선점형 멀티태스킹이다.
즉, 코루팀은 병행성(=동시성, concurrency)이지만 병렬성(parallelism)은 아니다.
※ 병행성과 병렬성?
병행성(=동시성)은 물리적으로 병렬 실행은 아니지만 마치 동시에 실행되는 것처럼 보이는 것이다.
병행성은 논리적인 개념이며, 실제로는 시간분할적으로 나눠 사용한다.
e.g. 한 손으로 두 개의 종이에 번갈아 그림을 그리는 것.
병렬성은 물리적으로, 실제로 동시에 작업이 처리되는 것이다.
e.g. 두 손으로 각각 종이에 그림을 동시에 그리는 것.
코루틴이 가지는 장점
- 협력형 멀티태스킹
- Co + routine
- 진입점과 탈출점이 여러 개여서 꼭 return을 만나지 않더라도 언제든지 서브루틴 실행 도중에 나갈 수 있고, 다시 나갔던 지점으로 돌아올 수도 있다.
- 동시성 프로그래밍 지원
- 함수를 중간에 빠져나왔다가 다른 함수에 진입하고 다시 돌아와 멈췄던 부분부터 다시 시작할 수 있다.
- 동시성 프로그래밍 = 왔다갔다 / 병렬성 프로그래밍 = 둘이 동시에
- 경량 스레드라고도 부른다.
- 목적이 스레드와 같지만 성능이 더 좋고 가볍다.
- 실행 중이던 코루틴이 중지되면, 현재 동일한 스레드 내에서 재개할 다른 코루틴을 찾는다.
- 같은 스레드 내에서 찾는 것이기 때문에 switch 비용 오버헤드가 없다.

- 쉬운 비동기 처리
- 코루틴을 통해 비동기 처리 코드를 쉽고 가독성 있게 작성할 수 있다.
- 동기 방식으로 비동기 프로그래밍을 가능하게 한다.
:: 참고자료 ::
https://ko.wikipedia.org/wiki/%EC%BD%94%EB%A3%A8%ED%8B%B4
코루틴 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 코루틴(coroutine)은 루틴의 일종으로서, 협동 루틴이라 할 수 있다(코루틴의 "Co"는 with 또는 together를 뜻한다). 상호 연계 프로그램을 일컫는다고도 표현가능하다.
ko.wikipedia.org
https://eocoding.tistory.com/88
코루틴(coroutine)에 대하여. 1편. 코루틴을 왜 쓸까?
코루틴(Coroutine)? 실행의 지연과 재개를 허용함으로써, 비선점적 멀티태스킹을 위한 서브 루틴을 일반화한 컴퓨터 프로그램 구성요소. 이제 진하게 칠한 단어를 하나씩 공부해보자! 1. 루틴과 서
eocoding.tistory.com
'CS > 밑바닥' 카테고리의 다른 글
| 동기와 비동기, 블로킹과 논블로킹 (0) | 2024.06.26 |
|---|---|
| 콜백 함수와 비동기 프로그래밍 (0) | 2024.06.26 |
| 프로그램이 실행될 때 - 운영 체제, 프로세스, 스레드 (0) | 2024.06.18 |
| (~ing)프로그래머가 코드를 작성할 때 일어나는 일 (2) - 컴파일러와 링커 (1) | 2024.06.15 |
| 프로그래머가 코드를 작성할 때 일어나는 일 (1) - 프로그래밍 언어의 탄생 (0) | 2024.06.12 |