채널 방향과 파이프라인 패턴
읽기 전용·쓰기 전용 채널과 파이프라인
채널 방향과 파이프라인 패턴은(는) CoddyKit의 무료 Go Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Go Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
방향성 채널 타입
Go에서는 타입 시그니처에서 채널을 송신 전용 또는 수신 전용으로 제한할 수 있습니다. 이를 통해 의도를 문서화하고 잘못된 사용을 방지합니다:
package main
// send-only: can only send, not receive or close (close is allowed by sender)
func sender(out chan<- int) {
out <- 42
}
// receive-only: can only receive, not send or close
func receiver(in <-chan int) int {
return <-in
}
// bidirectional: can do both
func relay(in <-chan int, out chan<- int) {
out <- <-in
}채널 방향 변환
양방향 채널은 어느 방향성 타입으로든 암시적으로 변환할 수 있지만, 방향성 타입을 양방향 타입으로 변환할 수는 없습니다:
package main
import "fmt"
func produce(out chan<- int) { out <- 1; close(out) }
func consume(in <-chan int) { fmt.Println(<-in) }
func main() {
ch := make(chan int) // bidirectional
go produce(ch) // auto-converts to chan<- int
consume(ch) // auto-converts to <-chan int
// chan<- int cannot be converted back to <-chan int
}파이프라인: 1단계 — 생성기
파이프라인은 각 단계가 이전 단계의 출력 채널에서 읽는 방식으로 goroutine을 연결합니다. 생성기는 첫 번째 단계입니다:
package main
import "fmt"
func generate(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func main() {
ch := generate(2, 3, 4, 5)
for v := range ch { fmt.Println(v) }
}파이프라인: 2단계 — 변환
중간 단계는 한 채널에서 수신하고, 값을 변환한 다음 다른 채널로 보냅니다:
package main
import "fmt"
func generate(nums ...int) <-chan int {
out := make(chan int)
go func() { for _, n := range nums { out <- n }; close(out) }()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for v := range in { out <- v * v }
close(out)
}()
return out
}
func main() {
for v := range square(generate(2, 3, 4, 5)) {
fmt.Println(v) // 4, 9, 16, 25
}
}파이프라인: 전체 3단계 예제
생성, 변환, 필터링의 세 단계를 연결합니다:
package main
import "fmt"
func gen(nums ...int) <-chan int {
c := make(chan int)
go func() { for _, n := range nums { c <- n }; close(c) }()
return c
}
func double(in <-chan int) <-chan int {
c := make(chan int)
go func() { for v := range in { c <- v * 2 }; close(c) }()
return c
}
func evens(in <-chan int) <-chan int {
c := make(chan int)
go func() { for v := range in { if v%2 == 0 { c <- v } }; close(c) }()
return c
}
func main() {
for v := range evens(double(gen(1,2,3,4,5))) {
fmt.Println(v) // 2, 4, 6, 8, 10
}
}완료 채널을 사용한 파이프라인 취소
완료 채널을 전달하면 취소될 때 파이프라인 단계가 일찍 종료되도록 할 수 있습니다:
package main
import "fmt"
func gen(done <-chan struct{}, nums ...int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for _, n := range nums {
select {
case out <- n:
case <-done: // cancel signal
return
}
}
}()
return out
}
func main() {
done := make(chan struct{})
ch := gen(done, 1, 2, 3, 4, 5)
fmt.Println(<-ch) // 1
close(done) // cancel remaining work
fmt.Println("pipeline cancelled")
}분산: 작업 배분
분산은 하나의 채널에서 여러 goroutine으로 작업을 나누어 병렬로 처리합니다:
package main
import ("fmt"; "sync")
func fanOut(in <-chan int, workers int) []<-chan int {
outs := make([]<-chan int, workers)
for i := 0; i < workers; i++ {
out := make(chan int)
outs[i] = out
go func() {
for v := range in { out <- v * v } // each worker processes
close(out)
}()
}
return outs
}
func main() {
fmt.Println("fan-out distributes work to multiple goroutines")
_ = sync.WaitGroup{}
}집계: 채널 병합
팬인은 여러 채널을 하나로 병합합니다:
package main
import ("fmt"; "sync")
func merge(cs ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for _, c := range cs {
wg.Add(1)
c := c
go func() { defer wg.Done(); for v := range c { out <- v } }()
}
go func() { wg.Wait(); close(out) }()
return out
}
func gen(nums ...int) <-chan int {
c := make(chan int)
go func() { for _, n := range nums { c <- n }; close(c) }()
return c
}
func main() {
for v := range merge(gen(1,2), gen(3,4), gen(5,6)) {
fmt.Println(v)
}
}파이프라인 모범 사례
파이프라인 설계 원칙:
- 각 단계에서는 고루틴이
<-chan에서 읽고chan<-에 쓰며, 작업이 끝나면 출력을 닫습니다 - 채널은 생산자만 닫아야 하며 소비자는 절대 닫지 않습니다
- 취소를 위해 완료 채널(또는 컨텍스트)을 전달합니다
- 모든 함수 시그니처에서 방향성 채널 형식을 사용합니다
- 고루틴 누수를 방지하려면 취소할 때 채널을 비웁니다
실제 파이프라인: CSV 처리
파이프라인은 데이터 처리에서 특히 유용합니다. 줄을 읽고, 구문 분석하고, 필터링하고, 변환합니다:
package main
import ("fmt"; "strings")
func splitLines(data string) <-chan string {
out := make(chan string)
go func() {
for _, line := range strings.Split(data, "\n") {
if line != "" { out <- line }
}
close(out)
}()
return out
}
func main() {
csv := "alice,30\nbob,25\ncarol,35"
for line := range splitLines(csv) {
parts := strings.Split(line, ",")
fmt.Printf("name=%s age=%s\n", parts[0], parts[1])
}
}빠른 확인
함수 시그니처에서 방향성 채널 형식을 사용하는 목적은 무엇입니까?
복습: 채널 방향과 파이프라인
요약:
chan<- T는 보내기 전용이고<-chan T는 받기 전용입니다. 의도를 명확히 기록하고 컴파일 시 안전성을 보장합니다- 파이프라인은 각 고루틴이 한 채널에서 읽고 다른 채널에 쓰도록 연결합니다
- 팬아웃: 하나의 입력 채널 → 여러 고루틴
- 팬인: 여러 채널 → 하나로 병합
- 항상 송신자가 채널을 닫고, 취소에는 완료 채널을 사용합니다
AI 튜터와 함께 Go을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 51
- 레슨
- 203
자주 묻는 질문
“채널 방향과 파이프라인 패턴” 강의는 무료인가요?
네 — “채널 방향과 파이프라인 패턴” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Go Academy 강의 전체를 잠금 해제할 수 있습니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“채널 방향과 파이프라인 패턴”에서 뭘 배우나요?
읽기 전용·쓰기 전용 채널과 파이프라인 브라우저에서 직접 실행하는 실습 코드로 Go Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Go Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Go Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“채널 방향과 파이프라인 패턴” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Go Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Go Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.