Search
Duplicate
🧵

코루틴, 파이버, 스레드

간단소개
코루틴, 파이버에 대해 간단히 알아보자
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
시스템
개발지식
Scrap
태그
코루틴
파이버
스레드
multithread
9 more properties
제목과는 달리 스레드와 스케줄링에 대해서는 설명하지 않습니다.

코루틴 (coroutine)

코루틴은 단순히 실행을 멈췄다가 나중에 재개할 수 있는 함수입니다.
int do_something() { return 1; // 1을 리턴하며 실행을 종료 return 2; // 이미 종료했으므로 이후로는 절대 실행되지 않음 return 3; }
C
복사
함수의 예시. 종료하고 나면 재개할 수 없습니다. 실제로는 1만 리턴합니다.
generator<int> do_something() { co_yield 1; // 1을 리턴하고 실행을 멈춤. 나중에 재개 가능 co_yield 2; // 재개하면 2를 리턴하고 실행을 멈춤 co_yield 3; // 재개하면 3을 리턴하고 실행을 멈춤 // ... co_return 42; // 재개하면 42를 리턴하고 실행을 종료 }
C++
복사
코루틴의 예시. 멈췄다가도 나중에 재개할 수 있습니다.
일반 함수랑 똑같이 쓸 수 있는 건 아니고, 호출하면 코루틴을 관리할 수 있는 객체를 리턴합니다.
그 객체를 통해 코루틴에 값을 전달하거나 실행을 재개하는 등의 작업이 가능합니다.
물론 그런 역할을 하는 객체를 만들 때 코루틴이 반드시 필요한 것은 아닙니다.
단지 작은 함수 여러개로 나뉠 것을 함수 하나로 만들 수 있게 하는 syntactic sugar일 뿐입니다.
generator<int> do_something() { // ... co_yield i; // 예를 들어 여기서 실행을 멈춘 코루틴을 재개하면 i = i * 2; co_yield i; // 여기까지만 실행될 것이고 i = f(i, 4); co_yield i - 2; // ... } // 그 상태의 코루틴을 재개하는 것은 이 함수를 실행하는 것과 비슷합니다. t_int_and_f do_something_internal_41(t_do_something_context *context) { context->i = context->i * 2; // 여기서 context는 코루틴 관리 객체에 포함! return ((t_int_and_f){context->i, do_something_internal_42}); } t_int_and_f do_something_internal_42(t_do_something_context *context) { context->i = f(context->i, 4); // 마찬가지로 yield 쓸 때마다 이런 함수들... return ((t_int_and_f){context->i - 2, do_something_internal_43}); }
C++
복사
이해를 돕기 위한 예시. 실제 C++20의 코루틴과는 정말 많이 다릅니다!
코루틴은 스케줄링이나 스레드와는 전혀 연관이 없습니다.
단지 실행을 멈췄다가 재개할 수 있는 함수일 뿐입니다.

파이버 (fiber)

스레드는 선점형 스케줄링을 사용하며, 스케줄링을 OS가 관리합니다.
파이버는 스레드와 비슷하지만, 파이버는 비선점형 스케줄링을 사용합니다.
스레드는 작업이 끝났는지와 상관 없이 제어권을 운영체제가 강제로 넘겨버립니다.
파이버는 비선점형 스케줄링으로, 스스로 제어권을 양도해야 다른 파이버가 작업할 수 있습니다.

코루틴으로 파이버 만들기

코루틴은 파이버와 정말 비슷합니다.
코루틴에 스케줄링만 추가하면 파이버가 됩니다!
코루틴이 yield(, await, return)하면 제어권이 양도됩니다.
이 점을 이용해 간단히 코루틴에 스케줄링을 추가하면 파이버를 만들 수 있습니다.
물론 파이버의 스케줄링에 스레드를 활용할 수 있습니다. (파이버는 스레드와 관련 없습니다.)

파이버가 스레드보다 좋은 경우

스레드가 코어의 개수보다 많은 경우, 운영체제가 제어권을 강제로 넘겨주게 됩니다.
그런 경우 그에 따른 불필요한 context switching이 자주 발생하며 그 비용도 높은 편입니다.
파이버를 사용하면 불필요한 context switching이 발생하지 않도록 만들 수 있습니다.
그러면서 멀티 코어를 활용하려면 스케줄링에 스레드를 코어 개수만큼만 사용하면 됩니다.

파이버 예시

자바스크립트의 async 함수도 파이버입니다.
자바스크립트 런타임(브라우저나 Node.js 등)에 스케줄링이 내장되어 있습니다.