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 처리 패턴으로 넘어가면 좋다.
'backend' 카테고리의 다른 글
| Go 프로젝트 구조와 패키지 설계: 실무에서 흔히 쓰는 기준 정리 (0) | 2026.01.19 |
|---|---|
| Go 언어 select 문 정리: 여러 channel을 동시에 다루는 방법 (0) | 2026.01.18 |
| Go 언어 goroutine과 동시성 기초: 병렬 처리의 기본 단위 이해하기 (0) | 2026.01.16 |
| Go 언어 에러 처리 방식 정리: error 인터페이스와 실전 패턴 (0) | 2026.01.15 |
| Go 언어 defer 정리: 자원 관리와 실행 순서 이해하기 (0) | 2026.01.14 |