backend

Go 언어 channel 기초: goroutine 간 통신과 동기화 방법

mirabo01 2026. 1. 17. 21:59

goroutine의 개념을 이해했다면, 이제 거의 항상 함께 사용되는
channel을 다룰 차례다.

goroutine이 “동시에 실행되는 작업 단위”라면,
channel은 그 작업들 사이를 연결하는 통로에 해당한다.
Go에서는 공유 메모리보다 메시지 전달을 우선하는 방식으로 동시성을 설계한다.

이 글에서는

  • channel의 기본 개념
  • 송수신 방식과 동작 특성
  • 실제로 자주 사용하는 패턴

을 중심으로 정리한다.


channel이란 무엇인가

channel은 값을 주고받기 위한 통로다.

ch := make(chan int)
  • chan 타입 형태로 선언
  • 같은 타입의 값만 송수신 가능

goroutine 간에 값을 안전하게 전달하기 위한 수단이며,
락(lock)을 직접 다루지 않아도 동기화를 가능하게 해준다.

[이미지: Go channel 기본 구조]


channel로 값 보내고 받기

값 보내기 (send)

ch <- 10

값 받기 (receive)

v := <-ch

이 문법은 처음 보면 조금 낯설지만,
“화살표 방향으로 값이 이동한다”고 생각하면 이해가 쉽다.


channel은 기본적으로 blocking이다

channel의 가장 중요한 특징은 블로킹(blocking) 이다.

ch <- 10   // 받는 쪽이 없으면 대기
v := <-ch  // 보내는 쪽이 없으면 대기
  • 송신자는 수신자가 나타날 때까지 대기
  • 수신자는 송신자가 나타날 때까지 대기

이 특성 덕분에 channel은
동기화 도구로도 자연스럽게 사용된다.

[이미지: channel blocking 동작 흐름]


goroutine과 channel 기본 예제

func worker(ch chan int) {
    v := <-ch
    fmt.Println("received:", v)
}

func main() {
    ch := make(chan int)
    go worker(ch)
    ch <- 42
}
  • goroutine이 channel에서 값을 기다린다
  • main에서 값을 보내며 동기화가 이루어진다

이 구조는 Go 동시성 코드의 가장 기본적인 형태다.


버퍼드 channel (Buffered Channel)

channel은 버퍼를 가질 수도 있다.

ch := make(chan int, 2)
  • 버퍼 크기만큼은 송신 시 바로 저장 가능
  • 버퍼가 가득 차면 그때부터 blocking
ch <- 1
ch <- 2
// 여기까지는 대기 없음

실제로 써보면,
버퍼드 channel은 비동기 큐처럼 동작한다.

⚠️ 주의할 점
버퍼가 있다고 해서 무조건 비동기 처리가 되는 것은 아니다.
버퍼 크기를 넘는 순간, 다시 blocking이 발생한다.


channel을 통한 작업 분리 패턴

channel은 보통 이런 역할로 사용된다.

  • 작업 전달
  • 결과 수집
  • 상태 신호 전달
jobs := make(chan int)
results := make(chan int)
  • 하나는 입력
  • 하나는 출력

이 패턴은 워커 풀(worker pool)이나 파이프라인 구조로 자주 확장된다.

[이미지: channel 기반 작업 파이프라인 구조]


channel 닫기(close)

close(ch)
  • 더 이상 값을 보내지 않겠다는 신호
  • 받는 쪽에서는 이를 감지할 수 있다
v, ok := <-ch
  • ok == false → channel이 닫힘

⚠️ 주의할 점

  • channel은 보내는 쪽에서만 닫는다
  • 닫힌 channel에 값을 보내면 panic 발생

range로 channel 순회하기

for v := range ch {
    fmt.Println(v)
}
  • channel이 닫힐 때까지 반복
  • 값 수신 + 종료 처리를 함께 표현 가능

실무에서 결과 수집 코드에 자주 등장하는 패턴이다.


channel 사용 시 흔한 오해

  • channel은 단순한 큐가 아니다
  • channel은 만능 동기화 도구가 아니다
  • goroutine 수명 관리를 자동으로 해주지 않는다

channel을 쓰면 코드가 깔끔해지긴 하지만,
설계를 잘못하면 오히려 흐름을 파악하기 어려워질 수 있다.


정리

channel은
goroutine 사이의 통신 규칙을 코드로 표현하는 도구다.

  • 기본적으로 blocking
  • 동기화와 데이터 전달을 동시에 해결
  • close와 range를 함께 쓰면 흐름이 명확해진다

goroutine과 channel을 함께 이해해야
Go 동시성의 큰 그림이 보이기 시작한다.

다음 글에서는 channel을 한 단계 더 확장한 주제인
select 문과 다중 channel 처리 패턴으로 넘어가면 좋다.