Skip to content

iq-dev-lab/concurrency-models-compared

Repository files navigation

🧬 Concurrency Models Compared

"모든 동시성 모델은 결국 같은 두 질문 — '블로킹을 어떻게 피하는가'와 '공유 상태를 어떻게 보호하는가' — 에 다르게 답한 것이다"


"한 언어의 동시성을 잘 쓰는 것과, 모든 모델이 같은 트레이드오프 공간의 다른 점이라는 걸 아는 것은 다르다"

JVM Virtual Thread · Kotlin Coroutine · Go 고루틴 · Rust async · Swift async/Actor · JS Event Loop — 6개 동시성 모델을 한자리에 놓고 같은 과제를 6번 풀어 효율·안전성·표현력의 축에서 비교합니다. 왜 모두 협력적 스케줄링으로 수렴했는가, 그리고 안전성에선 왜 갈라졌는가.


GitHub JVM Kotlin Go Rust Swift Node Docs License


🎯 이 레포에 대하여

동시성 자료는 언어별로는 넘쳐납니다. 하지만 대부분은 "한 언어 안에서 어떻게 쓰나" 에서 멈춥니다. 이 레포는 언어가 아니라 질문으로 챕터를 나누고, 각 질문에 대해 6모델의 답을 나란히 놓습니다.

일반 자료 이 레포
"고루틴 = 코루틴" 고루틴은 스택풀 + 런타임 스케줄러, 코루틴은 스택리스 + 컴파일러 상태머신 — 같은 결과를 완전히 다른 방법으로
"async/await는 JS 문법" Kotlin·Rust·Swift·JS의 async가 모두 같은 상태머신 변환이라는 점, 그리고 색깔 함수 문제가 만드는 분기
"Rust는 안전하다" 안전성을 어디서 보장하는가 — Rust(컴파일 타임 타입), Swift(컴파일 타임 격리), JVM(런타임 락), Go(관례 + race detector)
"Virtual Thread = 코루틴 대체" VT는 JVM 변경으로 얻은 런타임 다중화, 코루틴은 컴파일러 변환 — 색깔 함수의 유무가 만드는 본질적 차이
"구조적 동시성은 Kotlin 거" Kotlin·Swift·Java가 독립적으로 같은 결론에 도달한 수렴점, 그러나 Go의 누수 위험이 끝까지 남는 이유
단일 모델 설명 동일 과제 6언어 구현 — 1만 동시 작업 + 집계 + 타임아웃 + 취소를 같은 부하로 측정
추상적 비교 트레이드오프 공간을 2축 좌표(컴파일/런타임 안전 × 색깔 유무)에 6모델을 플롯

선행 학습 권장: 이 레포는 6개 단일 언어 deep-dive 레포의 종합입니다. 한 언어라도 먼저 보고 오면 비교의 깊이가 다릅니다 — 🔗 레포 연결 참고.


🚀 빠른 시작

질문별로 챕터가 구성되어 있습니다. 각 챕터의 첫 문서부터 바로 시작하세요.

Ch1 근본 질문 Ch2 효율 Ch3 일시정지 Ch4 안전 Ch5 구조 Ch6 6구현 Ch7 종합


🧭 핵심 프레임 — 두 질문, 한 좌표

모든 동시성 모델 = 두 질문에 대한 답의 조합

  ① 효율: 스레드를 어떻게 싸게 쓰나?
       OS 스레드(비쌈) → 경량 단위로 다중화
       → 6모델 모두 "양보 지점에서 멈추고 스레드 재사용"으로 수렴
       → 갈라지는 지점: 스택풀(Go·VT) vs 스택리스(Kotlin·Rust·Swift·JS)

  ② 안전: 공유 상태를 어떻게 지키나?
       락(JVM)     — 런타임 보장, 실수 가능
       Actor(Swift) — 컴파일 타임 격리
       소유권(Rust) — 컴파일 타임 타입, 런타임 비용 0
       채널(Go)    — 공유 대신 통신(CSP)

트레이드오프 공간:
                컴파일 타임 안전 ◄─────────────────► 런타임/관례
  Rust ●                                                       ● JVM
  Swift ●                                              ● Go
                       색깔 있음 ◄─────────────────► 색깔 없음
  Rust/JS ●                                          ● Go/JVM VT

📚 전체 학습 지도

💡 각 섹션을 클릭하면 상세 문서 목록이 펼쳐집니다. 모든 문서에서 최소 2~3개 모델을 나란히 비교합니다.


🔹 Chapter 1: 동시성의 근본 문제

핵심 질문: 모든 동시성 모델이 답하는 두 질문은 무엇이며, 이 레포는 어떤 축으로 그것들을 비교하는가?

두 질문, 블로킹의 비용, 동시성 vs 병렬성, 레이스의 본질까지 (5개 문서)
문서 다루는 내용
01. 두 가지 근본 질문 모든 모델이 답해야 하는 ① 스레드 효율 ② 상태 안전, 그리고 둘이 독립적인 트레이드오프 축임을 보이는 6모델 매핑
02. 블로킹의 비용 OS 스레드 블로킹이 비싼 이유 — 1MB 스택·커널 TCB·컨텍스트 스위치, C10K 문제, linux-for-backend 레포로 깊이 위임
03. 동시성 vs 병렬성 "Concurrency is not parallelism" (Rob Pike) — 단일 코어에서도 동시성이 의미 있는 이유, 6모델이 각각 어디에 무게를 두는가
04. 공유 상태와 레이스 데이터 레이스의 본질(메모리 모델·재정렬·가시성), computer-architecture-deep-dive로 깊이 위임, 6모델이 어디에서 막는가
05. 비교 프레임 설정 이 레포가 사용할 4개 평가 축 — 효율(처리량·메모리) / 안전성(보장 위치) / 표현력(색깔·구조) / 복잡도(러닝커브·디버깅)

🔹 Chapter 2: 스레드 효율 — 경량 실행 단위

핵심 질문: OS 스레드가 비싼 이유와, 6모델이 그 비용을 피한 서로 다른 방법은 무엇인가?

OS 스레드, 협력적 스케줄링, VT, 고루틴, 상태머신, 나란히 측정까지 (6개 문서)
문서 다루는 내용
01. OS 스레드는 왜 비싼가 1MB 스택·TCB·clone 시스템 콜·커널 스케줄러 — 수만 개가 원리적으로 불가능한 이유, 6모델이 공유하는 출발점
02. 협력적 스케줄링 — 공통 답 6모델 모두가 도달한 결론: 양보 지점에서 멈추고 재개 — preemptive와의 차이, 각 모델이 양보를 어디에 두는가
03. Virtual Thread (JVM) 캐리어 스레드 위 다중화, 블로킹 코드를 그대로 쓸 수 있는 특이점, pinning 함정, java-concurrency-deep-dive로 위임
04. 고루틴 (Go) M:N GMP 스케줄러, 2KB 시작 가변 스택, 워크 스틸링 — 런타임이 자체 스케줄러를 갖는 모델, go-deep-dive로 위임
05. 상태머신 코루틴 (Kotlin·Rust·Swift·JS) 4개 언어가 독립적으로 도달한 같은 변환 — suspend/async → 상태머신 객체, 동형성 강조
06. 측정 비교 — 1만 동시 작업 같은 부하(1만×100ms 대기)를 6모델로, 메모리·생성 시간·처리량을 같은 그래프에, OS 스레드 1만(불가)을 대조군으로

🔹 Chapter 3: 일시정지의 메커니즘

핵심 질문: "양보"를 구현하는 두 가지 방식 — 스택풀과 스택리스 — 은 무엇이 다르며, 색깔 함수는 어디서 생기는가?

두 방식, 상태머신 변환, 스택풀, 색깔 함수, Continuation까지 (6개 문서)
문서 다루는 내용
01. 스택풀 vs 스택리스 두 가지 갈래 — Go·VT(스택 보유) vs Kotlin·Rust·Swift·JS(상태머신) — 이 분기가 만드는 결과들의 전체 지도
02. 상태머신 변환의 동형성 Kotlin suspend, Rust async fn, Swift async바이트코드/IR 레벨에서 같은 상태머신이 됨을 디컴파일로 확인
03. 스택풀 코루틴 — Go·VT 내부 고루틴의 stack growth check·세그먼티드 스택, VT의 캐리어 위 컨텍스트 스위치 — 실제 스택을 양보하는 메커니즘
04. 색깔 함수 문제 "What Color is Your Function?" (Bob Nystrom) — async 전염(JS/Rust/Kotlin/Swift) vs 무색(Go/VT), 타입 시스템 격리의 가치와 비용
05. Continuation — 공통 추상 일시정지/재개의 저수준 — Kotlin Continuation, Rust Future::poll+Waker, Swift task UnsafeContinuation — 같은 개념의 다른 이름
06. 같은 비동기 로직 6모델 동일한 "fetch → transform → fetch → aggregate" 로직을 6언어로 — 색깔 유무가 코드 모양을 어떻게 바꾸나

🔹 Chapter 4: 상태 보호 — 안전성

핵심 질문: 같은 데이터 레이스가 Rust에선 컴파일 에러, JVM에선 런타임 버그가 되는 이유는?

네 가지 전략, 락, Actor, 소유권, 채널, 보장 위치 비교까지 (7개 문서)
문서 다루는 내용
01. 네 가지 전략 ① 공유+락 ② 격리(Actor) ③ 소유권+타입 ④ 통신(채널) — 6모델이 어떤 전략을 주력으로 채택했는가의 매핑
02. 공유 + 락 (JVM) synchronized·ReentrantLock·volatile·CAS, 런타임 보장의 한계 — 잊으면 끝, java-concurrency-deep-dive로 위임
03. 격리 — Actor (Swift) actor가 가변 상태를 직렬화하는 메커니즘, Swift 6의 컴파일 타임 Sendable 검사, swift-concurrency-deep-dive로 위임
04. 소유권 + 타입 (Rust) Send/Sync 자동 트레이트가 컴파일 타임에 레이스를 막는 원리, 런타임 비용 0의 안전성, rust-deep-dive로 위임
05. 통신 — 채널 (Go) "Don't communicate by sharing memory; share memory by communicating" — CSP, select, go-deep-dive로 위임
06. 안전성 위치 비교 어디서 막는가의 4단 분기 — 컴파일 타임 타입(Rust) / 컴파일 타임 격리(Swift) / 런타임 검사(JVM) / 관례+도구(Go)
07. 같은 레이스 6모델 동일한 공유 카운터 증가 코드를 6언어로 — Rust는 컴파일 거부, Swift는 경고, Go는 -race로 검출, JVM은 실리콘 운에 맡김

🔹 Chapter 5: 구조와 취소

핵심 질문: 비동기 작업이 떠도는 것을 막는 메커니즘은 무엇이며, 왜 여러 언어가 같은 결론에 도달했는가?

구조적 동시성, 취소 전파, 누수 위험, 에러 전파까지 (5개 문서)
문서 다루는 내용
01. 구조적 동시성 Nathaniel Smith의 원안 — 작업 트리·생명주기를 부모 함수 스코프에 묶기, Kotlin·Swift·Java가 독립적으로 수렴한 결론
02. 취소 전파 부모 취소 → 자식 취소가 자동인 모델(Kotlin·Swift) vs 수동인 모델(Go context, JS AbortController) — 안전성 차이
03. 비구조적 위험 떠도는 태스크 — Go의 고루틴 누수, Kotlin의 GlobalScope 안티패턴, JS의 unhandled Promise — 같은 함정의 다른 이름
04. 에러 전파 동시 작업 중 하나가 실패할 때의 전파 정책 — Kotlin SupervisorJob, Swift withThrowingTaskGroup, Go errgroup, JS Promise.all vs allSettled
05. 같은 시나리오 6모델 "여러 작업 동시 실행 + 하나 실패 시 전체 취소 + 타임아웃" — 6언어 구현을 같은 코드 모양으로 정렬해 비교

🔹 Chapter 6: 같은 문제, 6가지 구현

핵심 질문: 동일한 동시성 과제를 6개 언어로 짜면 코드 모양측정값이 어떻게 다르게 나오는가?

과제 정의, 6언어 구현, 코드 비교, 측정 비교까지 (6개 문서) — comparisons/ 에 실행 가능 코드
문서 다루는 내용
01. 과제 정의 통일된 과제 — 동시 API 호출 N개 + 집계 + 5초 타임아웃 + 하나 실패 시 전체 취소, 입출력 명세, 측정 지표
02. 구현 ① JVM Virtual Thread / ② Kotlin Coroutine 두 JVM 솔루션 — VT는 블로킹 그대로, Kotlin은 coroutineScope+async — 같은 런타임, 다른 코드
03. 구현 ③ Go 고루틴+채널 / ④ Rust async (Tokio) Go: errgroup+context, Rust: tokio::try_join!+select! — 스택풀 vs 스택리스의 코드 모양 차이
04. 구현 ⑤ Swift async/Actor / ⑥ JS async/Promise Swift: withThrowingTaskGroup+actor, JS: Promise.all+AbortController — 구조적 동시성의 언어 차원 통합도
05. 코드 비교 — 가독성·안전성·표현력 6언어 구현을 나란히 한 표에 — 줄 수, 명시적 취소 코드 비율, 에러 처리 명확성, 타입 안전성 점수
06. 측정 비교 — 처리량·메모리·지연 같은 부하(N=10,000)에서 6모델의 p50/p99 지연, RSS, GC pause, CPU 활용도를 같은 그래프

🔹 Chapter 7: 트레이드오프 종합

핵심 질문: 6모델이 왜 효율에선 수렴했고 안전성에선 갈라졌는가, 그리고 새 언어를 만나도 빠르게 분석할 수 있는 프레임은?

평가 축, 수렴, 발산, 선택 가이드, 종합 지형도까지 (5개 문서)
문서 다루는 내용
01. 평가 축 종합 효율·안전성 위치·색깔·런타임 유무·복잡도 — 5축에 6모델을 한 표로 정렬, 각 칸의 점수 근거
02. 왜 수렴했나 협력적 경량 스케줄링으로 모두 간 이유 — OS 추상화의 한계, 하드웨어 코어 정체, I/O 비중 증가
03. 왜 발산했나 안전성 철학의 분기 — 타입 (Rust) vs 격리 (Swift) vs 런타임 (JVM) vs 관례 (Go) — 언어 설계 가치관의 차이
04. 선택 가이드 워크로드 × 팀 × 생태계에 따른 모델 이해 — "어느 게 좋다"가 아니라 "이 상황에선 이 트레이드오프가 맞다"
05. 동시성 모델 지형도 종합 — 새 언어의 동시성을 만나도 이 프레임으로 1시간 안에 파악, 향후 등장할 모델의 예측(예: Mojo, Zig async)

🗺️ 목적별 학습 경로

🟢 "고루틴 = 코루틴?"을 명확히 구분하고 싶다 — 면접/개념 정리 (1주)
Day 1  Ch1-01  두 가지 근본 질문 (틀 잡기)
Day 2  Ch2-04  고루틴 (Go) — 스택풀 + 런타임 스케줄러
Day 3  Ch2-05  상태머신 코루틴 — 4언어 동형
Day 4  Ch3-01  스택풀 vs 스택리스 (핵심 분기)
Day 5  Ch3-04  색깔 함수 문제
Day 6  Ch2-06  측정 비교 — 1만 동시 작업
Day 7  Ch7-03  왜 발산했나 — 철학의 차이
🔵 모든 동시성 모델을 원리부터 비교하고 싶은 개발자 (7주)
Week 1  Chapter 1 전체 — 근본 문제와 평가 프레임
Week 2  Chapter 2 전체 — 효율의 6가지 답
Week 3  Chapter 3 전체 — 일시정지 메커니즘
Week 4  Chapter 4 전체 — 안전성의 4가지 전략
Week 5  Chapter 5 전체 — 구조와 취소
Week 6  Chapter 6 전체 — 같은 과제 6언어 구현 + 측정
Week 7  Chapter 7 전체 — 종합과 선택 가이드
🔴 새 언어의 동시성을 빠르게 평가하는 프레임이 필요한 개발자 (집중 코스)
핵심 경로 — "프레임 먼저, 사례는 나중"

Step 1  Ch1-01     두 질문 (효율 + 안전)
Step 2  Ch1-05     4개 평가 축
Step 3  Ch3-01     스택풀 / 스택리스 분기
Step 4  Ch3-04     색깔 함수 (타입 시스템 격리)
Step 5  Ch4-01     안전성 4전략
Step 6  Ch4-06     안전성 보장 위치
Step 7  Ch7-01     평가 축 종합 표
Step 8  Ch7-05     지형도 — 새 모델 평가 템플릿

목표: 처음 보는 언어의 동시성 모델을 1시간 안에
      "이 좌표의 이 점이다"라고 말할 수 있을 것
🟡 안전성 모델만 깊게 보고 싶은 개발자
Step 1  Ch1-04   레이스의 본질
Step 2  Ch4-01   네 가지 전략
Step 3  Ch4-02   락 (JVM) — 런타임
Step 4  Ch4-04   소유권 (Rust) — 컴파일 타임 타입
Step 5  Ch4-03   Actor (Swift) — 컴파일 타임 격리
Step 6  Ch4-05   채널 (Go) — CSP
Step 7  Ch4-07   같은 레이스 6모델 비교
Step 8  Ch7-03   왜 발산했나 — 철학의 분기

📖 각 문서 구성 방식

모든 문서는 동일한 10섹션 구조 + 이 레포의 정체성: 항상 다중 모델 나란히 비교.

섹션 설명
🎯 핵심 질문 이 문서를 읽고 나면 답할 수 있는 질문
🔍 왜 이게 존재하는가 6모델 공통의 문제 상황과 각 모델이 답해야 했던 압력
😱 흔한 오해 "코루틴 = 고루틴", "Rust는 무조건 안전" 같은 교차 모델 오해들
올바른 이해 각 모델이 왜 그런 답을 골랐는지의 설계 의도
🔬 내부 동작 원리 최소 2~3개 모델을 같은 표·다이어그램에 — 한 모델만 설명하지 않음
💻 실전 실험 동일한 과제를 여러 언어로 구현 (comparisons/ 에 실행 가능)
📊 측정 같은 부하·같은 머신·같은 그래프에 6모델 데이터 — 처리량·메모리·지연
🤔 트레이드오프 4개 평가 축(효율·안전·표현력·복잡도)에 각 모델을 플롯
📌 핵심 정리 한 화면 요약 — 6모델의 한 줄 비교
🤔 생각해볼 문제 교차 모델 사고 실험 + 해설

🔬 검증 환경

다언어 비교라 여러 런타임을 한 번에. docker-compose로 polyglot 환경, comparisons/에 동일 과제 6구현.

# Dockerfile — 6모델 비교용 polyglot
FROM ubuntu:24.04

RUN apt-get update && apt-get install -y \
    openjdk-21-jdk \              # JVM Virtual Thread (Project Loom)
    golang-1.22 \                 # 고루틴
    nodejs npm \                  # JS Event Loop
    curl build-essential

# Rust async (Tokio)
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y

# Kotlin (SDKMAN)
RUN curl -s "https://get.sdkman.io" | bash && \
    bash -c "source ~/.sdkman/bin/sdkman-init.sh && sdk install kotlin"

# Swift 6 (별도 멀티스테이지 또는 swift:6 베이스 이미지 권장)
# 핵심 — 같은 과제를 6언어로, 나란히 측정

# [효율 비교]  1만 동시 "100ms 대기" 작업
cd comparisons/10k-tasks
  ./run-jvm-vt.sh      # Virtual Thread
  ./run-kotlin.sh      # Coroutine + Dispatchers.IO
  ./run-go.sh          # goroutine
  ./run-rust.sh        # Tokio task
  ./run-swift.sh       # Task + TaskGroup
  ./run-node.sh        # async/await + Promise.all
  # 측정: 메모리(RSS), 생성 시간, 처리량
  # 대조: OS 스레드 1만 (불가/거대)

# [안전 비교]  공유 카운터에 1만 동시 증가
cd comparisons/shared-counter
  cargo build      # → Rust: 컴파일 에러 (Send/Sync 위반)
  swift build      # → Swift 6: 컴파일 경고 (Sendable)
  go build         # → 빌드 성공, go run -race 로 런타임 검출
  ./gradlew run    # → JVM: 런타임 레이스 (도구로 검출 필요)

# [색깔 비교]  async 전염 관찰
cd comparisons/function-coloring
  # Rust/JS:   async fn → 호출자도 async (전염)
  # Go/JVM VT: 일반 함수처럼 블로킹 코드 그대로 (무색)
  # Kotlin/Swift: suspend/async 키워드 + 구조적 동시성
검증 결과는 각 문서 📊 측정 섹션에 *같은 그래프*로 통합.
숫자는 머신마다 다르므로 절대값보다 비율/순위에 주목.

🔗 레포 연결

⬆️ 선행 학습 (이 비교의 입력 — 한 언어라도 먼저)
  java-concurrency-deep-dive       → Virtual Thread, 락, 메모리 모델
  kotlin-deep-dive                 → Coroutine, CPS 변환, 상태머신
  go-deep-dive                     → 고루틴, GMP 스케줄러, 채널
  rust-deep-dive                   → async/await, Send/Sync, Tokio
  swift-concurrency-deep-dive      → async/await, Actor, Sendable
  event-loop-async-deep-dive       → JS 이벤트 루프, Promise, 마이크로태스크

🤝 시너지
  computer-architecture-deep-dive  → 메모리 모델, 원자 연산, 캐시 일관성
  linux-for-backend-deep-dive      → 스레드 스케줄링, epoll/io_uring, C10K

🧬 본질 (이 레포의 위치)
  concurrency-models-compared      → 6개 단일 레포를 하나의 비교 프레임으로
                                     "한 언어 동시성"과 "트레이드오프 공간 이해"의 다리

🙏 Reference


⭐️ 도움이 되셨다면 Star를 눌러주세요!

Made with ❤️ by Dev Book Lab


"한 언어의 동시성을 잘 쓰는 것과, 모든 모델이 같은 트레이드오프 공간의 다른 점이라는 걸 아는 것은 다르다"

About

한 언어의 동시성을 잘 쓰는 것과, 모든 모델이 같은 트레이드오프 공간의 다른 점이라는 걸 아는 것은 다르다

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors