Menu
Coddy logo textTech

Channels & 통신

Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 60번째.

채널은 고루틴 간 통신을 위한 Go의 주요 메커니즘입니다. 고루틴은 메모리를 직접 공유하는 대신 채널을 통해 값을 보내고 받으며, 다음과 같은 Go의 철학을 따릅니다. "메모리를 공유하여 통신하지 말고, 통신하여 메모리를 공유하라."

chan 키워드와 함께 make 함수를 사용하여 채널을 생성하세요:

messages := make(chan string)

값을 보내고 받으려면 화살표 연산자 <-를 사용하세요. 화살표는 데이터 흐름의 방향을 가리킵니다:

func main() {
    messages := make(chan string)
    
    go func() {
        messages <- "hello"  // 채널로 전송
    }()
    
    msg := <-messages  // 채널에서 수신
    fmt.Println(msg)   // 출력: hello
}

기본적으로 송신과 수신은 상대편이 준비될 때까지 차단됩니다. goroutine이 "hello"를 보낼 때 main이 수신할 준비가 될 때까지 기다립니다. 이러한 차단 동작은 기본 제공 동기화를 제공합니다. time.Sleep이 필요하지 않습니다.

채널을 닫아 더 이상 값이 전송되지 않음을 알릴 수 있습니다. 수신자는 이를 감지할 수 있습니다.

close(messages)

msg, ok := <-messages
if !ok {
    fmt.Println("Channel closed")
}

채널에는 타입이 지정됩니다. chan string은 문자열만 전달할 수 있습니다. 이러한 타입 안전성은 goroutine이 올바른 데이터 타입으로 통신하도록 보장하여, 런타임이 아니라 컴파일 타임에 오류를 감지합니다.

challenge icon

챌린지

쉬움

goroutine이 channel을 통해 어떻게 통신하는지 보여 주는 message relay system을 만들어 보겠습니다. 각 단계가 동시에 실행되는 가운데 message가 서로 다른 처리 단계 사이를 흐르는 pipeline을 만들게 됩니다.

코드를 두 파일에 걸쳐 구성합니다:

  • relay.go: message 처리 pipeline을 Define합니다.

    ID (int) 및 Content (string) fields를 포함하는 Message struct를 Create합니다.

    pipeline의 서로 다른 단계를 나타내는 세 개의 function을 Implement합니다:

    • Producer(messages []Message, out chan Message) - message의 slice를 받아 각각을 output channel로 보냅니다. 모든 message를 보낸 후 channel을 close하여 완료를 알립니다.
    • Transformer(in chan Message, out chan Message) - input channel에서 message를 받고, 각 message의 content를 대문자로 변환한 다음 변환된 message를 output channel로 보냅니다. input channel이 close되면(두 값 receive 형식을 사용하여 감지) output channel을 close합니다.
    • Consumer(in chan Message) []string - input channel에서 모든 message를 받고 formatted string의 slice로 collect합니다. 각 string은 다음 형식을 따라야 합니다: Message [ID]: [Content]. channel이 close되면 slice를 반환합니다.
  • main.go: pipeline을 설정하고 concurrent message 흐름을 조정합니다.

    message의 수를 읽은 다음 각 message의 ID와 content를 읽습니다. message를 Create하고 세 pipeline 단계를 connect할 두 개의 channel을 설정합니다. Producer와 Transformer를 goroutine으로 Launch한 다음, 결과를 collect하기 위해 main goroutine에서 Consumer를 실행합니다. 각 결과를 별도의 line에 출력합니다.

다음 input이 제공됩니다:

  • Line 1: message 수 (integer)
  • Following lines: 각 message마다 두 line - message ID (integer), 그다음 content (string)

예를 들어, 다음이 주어졌을 때:

2
1
hello world
2
go channels

output은 다음과 같아야 합니다:

Message 1: HELLO WORLD
Message 2: GO CHANNELS

pipeline은 다음과 같이 흐릅니다: Producer가 message를 보냄 → Transformer가 대문자로 converts → Consumer가 결과를 collect하고 formatted합니다. 각 화살표는 concurrent 단계들을 connect하는 channel을 나타냅니다. 대문자 변환에는 strings package를 사용합니다.

직접 해보기

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 메시지 개수 읽기
	nLine, _ := reader.ReadString('\n')
	n, _ := strconv.Atoi(strings.TrimSpace(nLine))

	// 메시지 읽기
	messages := make([]Message, n)
	for i := 0; i < n; i++ {
		idLine, _ := reader.ReadString('\n')
		id, _ := strconv.Atoi(strings.TrimSpace(idLine))
		contentLine, _ := reader.ReadString('\n')
		content := strings.TrimSpace(contentLine)
		messages[i] = Message{ID: id, Content: content}
	}

	// TODO: 파이프라인 단계를 연결할 두 개의 채널 생성

	// TODO: Producer를 goroutine으로 실행

	// TODO: Transformer를 goroutine으로 실행

	// TODO: main goroutine에서 Consumer를 실행하고 결과 수집

	// TODO: 각 결과를 별도 줄에 출력
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Go 컴파일러