프로세스→스레드→코루틴은 격리·메모리 공유·생성 비용이 다른 실행 단위 계층이다. 스레드는 하나당 스택을 약 1MB씩 점유해 1만 개면 스택만 10GB라 OOM이 나지만, 코루틴은 소수의 OS 스레드 위에서 수만 개가 번갈아 돌기 때문에 같은 1만 개도 견딘다.
OS 스레드는 타임 슬라이스가 끝나면 OS가 CPU를 강제로 회수하는 선점형이고, 코루틴은 실행 주체가 스스로 양보해야 하는 협력적 방식이다. 그래서 코루틴은 I/O 대기 중 전환이 자연스럽지만, 양보하지 않는 CPU-bound 작업이 끼면 나머지가 전부 멈춘다.
어떤 동시성 도구를 쓸지는 작업의 성격이 결정한다. I/O 대기가 많으면 코루틴, CPU 연산이 많으면 OS 스레드, 메모리 격리가 필요하면 프로세스가 맞다.
같은 "동시에 실행"이라도 실행 단위에 따라 메모리 사용과 생성 비용이 크게 다르다. 세 단위는 격리 수준이 낮아질수록 가벼워지는 계층 관계다.
| 실행 단위 | 메모리 | 생성/전환 비용 | 특징 |
|---|---|---|---|
| 프로세스 | 완전히 격리, 메모리 비공유 | 생성 시 메모리 전체 복사 → 큼 | 안전하지만 무거움 |
| 스레드 | 프로세스 안에서 힙 공유 | 스레드당 스택 약 1MB, 컨텍스트 스위칭 발생 |
프로세스보다 가벼움 |
| 코루틴 | 소수의 OS 스레드 위에서 동작 | 컨텍스트 스위칭·복원 비용 거의 없음 | 수만 개를 한 스레드 위에서 번갈아 실행 |
핵심은 코루틴이 OS 스레드를 대체하는 게 아니라 그 "위"에서 돈다는 점이다. 실제 OS 스레드는 몇 개만 두고 그 위에서 코루틴 수만 개를 번갈아 실행하므로, 스레드 1만 개를 만들 때 드는 스택 비용과 OS 차원의 컨텍스트 스위칭을 회피한다. 스레드 1만 개는 스택만으로 10GB가 필요해 OOM으로 죽지만, 코루틴은 소수의 OS 스레드 위에서 돌기 때문에 같은 1만 개도 멀쩡하다. (보충) 코루틴은 적은 수의 OS 스레드에 다수의 코루틴을 매핑하는 M:N 방식으로 볼 수 있다.
스레드 1만 개의 스택 메모리 추정: 스레드당 스택 약 1MB × 10,000개 = 약 10GB. 이 스택 메모리만으로 일반적인 서버의 가용 메모리를 초과해 Out of Memory가 발생한다. 반면 코루틴 1만 개는 OS 스레드 몇 개 위에서 돌아 스택 비용이 그 소수 스레드 분량에 그치므로 같은 규모에서도 죽지 않는다.
코루틴이 가볍다고 만능은 아니다. 코루틴이 빛나는지 아닌지는 스케줄링 방식과 작업 성격에서 갈린다.
| 구분 | OS 스레드 | 코루틴 |
|---|---|---|
| 스케줄링 | 선점형(preemptive) — 타임 슬라이스가 끝나면 OS가 강제로 CPU 회수 | 협력적(cooperative) — 실행 주체가 스스로 양보해야 전환 |
| I/O 대기 | OS가 알아서 전환 | 대기 중 다른 코루틴으로 전환 → 효율적 |
| CPU 연산 독점 | OS가 강제로 끊어 공정 분배 | 양보 지점이 없으면 전환 불가 |
코루틴은 네트워크 응답 등을 기다리는 I/O 대기 동안 다른 코루틴으로 넘어가므로 적은 스레드로 많은 동시 작업을 처리한다. 그러나 CPU를 꽉 잡고 계산하는 작업에서는 양보할 틈이 없다. 협력적 스케줄링에서는 CPU-bound 작업이 양보하지 않으면 같은 스레드 위의 나머지 코루틴이 전부 멈춰버린다. 반면 OS 스레드는 선점형이라 한 작업이 CPU를 독점해도 OS가 강제로 CPU를 빼앗아 다른 작업에 분배한다.
화자의 마무리 정리다. 동시성 도구는 우열이 아니라 작업 성격에 맞춰 고른다.
| 작업 성격 | 적합한 도구 | 이유 |
|---|---|---|
| I/O 대기가 많음 | 코루틴 | 대기 중 전환으로 적은 스레드로 높은 동시성 |
| CPU 연산이 많음 | OS 스레드 | 선점형 스케줄링으로 강제 분배, 한 작업의 독점 방지 |
| 격리가 필요함 | 프로세스 | 메모리 비공유로 안전성 확보 |
무엇을 쓸지는 도구의 우열이 아니라 작업의 성격이 결정한다.