Go Academy · 강의

채널 방향과 파이프라인 패턴

읽기 전용·쓰기 전용 채널과 파이프라인

레슨 4/412개 단계

채널 방향과 파이프라인 패턴은(는) 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 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 고루틴 실행
  2. 비버퍼 채널
  3. 버퍼 채널
  4. 채널 방향과 파이프라인 패턴
← Go Academy(으)로 돌아가기