Buffered vs Unbuffered 채널
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 61번째.
지금까지 사용한 channel은 버퍼가 없는 channel입니다. 값을 저장할 capacity가 없습니다. 전송 작업은 다른 goroutine이 수신할 때까지 차단되고, 그 반대도 마찬가지입니다. Buffered channel은 내부 저장 공간을 추가하여, 즉시 수신자가 없어도 전송을 완료할 수 있게 합니다.
make에 capacity를 전달하여 버퍼링된 채널을 생성합니다:
// 언버퍼드 - 용량 0
unbuffered := make(chan int)
// 버퍼드 - 용량 3
buffered := make(chan int, 3)buffered channel에서는 buffer가 full일 때만 send가 block되고, buffer가 비어 있을 때만 receive가 block됩니다:
ch := make(chan string, 2)
ch <- "first" // 블록하지 않음 - 버퍼에 공간이 있음
ch <- "second" // 블록하지 않음 - 버퍼에 공간이 있음
// ch <- "third"는 블록됨 - 버퍼가 가득 참
fmt.Println(<-ch) // "first"
fmt.Println(<-ch) // "second"버퍼에 현재 몇 개의 items가 있는지 확인하려면 len(ch)을 사용하고, 전체 capacity에는 cap(ch)을 사용하세요.
each를 언제 사용할지: 버퍼가 없는 채널은 긴밀한 동기화를 제공합니다. 즉, 송신자는 수신자가 값을 받았다는 것을 알 수 있습니다. Buffered 채널은 송신자와 수신자의 타이밍을 분리하므로, 생산자와 소비자가 서로 다른 속도로 작업할 때 유용합니다. 그러나 Buffered 채널은 동기화 버그를 가릴 수 있으므로, 버퍼링을 사용할 특별한 이유가 없다면 버퍼가 없는 채널을 우선 사용하세요.
챌린지
쉬움버퍼가 있는 채널과 버퍼가 없는 채널의 차이를 보여 주는 batch processor를 만들어 보겠습니다. 생산자가 processor로 items를 보내는 시스템을 만들고, 버퍼가 있는 채널을 사용하여 두 작업의 타이밍을 분리하고 생산자가 먼저 작업할 수 있도록 합니다.
코드를 두 파일로 구성합니다.
processor.go: 채널을 사용한 batch processing 로직을 정의합니다.ID(int) 및Value(string) 필드가 있는Item구조체를 만듭니다.두 함수를 Implement합니다.
Producer(items []Item, out chan Item)- 각 item을 출력 채널로 보냅니다. 각 item을 보낸 후Produced item [ID]를 출력합니다. 모든 items를 보낸 후len(out)을 사용하여 버퍼에서 대기 중인 현재 items 수를Buffer has [count] items형식으로 출력합니다. 그런 다음 채널을 닫습니다.Consumer(in chan Item) []string- 입력 채널에서 items를 받아 형식이 지정된 문자열의 슬라이스로 수집합니다. 수신한 각 item의 문자열은 다음과 같아야 합니다:Consumed: [ID] - [Value]. 채널이 닫히면 슬라이스를 반환합니다.
main.go: 버퍼가 있는 채널을 설정하고 생산자와 소비자를 조정합니다.버퍼 capacity를 읽은 다음, items 수를 읽고, 이어서 각 item의 ID와 값을 읽습니다. 지정된 capacity로 버퍼가 있는 채널을 만듭니다. 먼저 Producer를 실행하여( goroutine으로 실행하지 않음) 버퍼를 채운 다음 Consumer를 실행하여 모든 items를 처리합니다. 각 consumed 결과를 별도의 줄에 출력합니다.
다음 입력이 제공됩니다.
- 1번째 줄: Buffer capacity (정수)
- 2번째 줄: items 수 (정수)
- 이후 줄: 각 item마다 두 줄 - item ID(정수), 그다음 해당 값(string)
예를 들어 다음이 주어졌다고 합시다.
3
3
1
apple
2
banana
3
cherry출력은 다음과 같아야 합니다.
Produced item 1
Produced item 2
Produced item 3
Buffer has 3 items
Consumed: 1 - apple
Consumed: 2 - banana
Consumed: 3 - cherryBuffer capacity가 3이면 producer가 blocking 없이 3개의 items를 모두 보낼 수 있으며, Consumer가 시작하기 전에 buffer에 3개의 items가 대기 중으로 표시됩니다. Buffer가 items 수보다 작다면 producer는 공간을 기다리며 block됩니다.
직접 해보기
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 버퍼 용량 읽기
line, _ := reader.ReadString('\n')
bufferCapacity, _ := strconv.Atoi(strings.TrimSpace(line))
// 항목 수 읽기
line, _ = reader.ReadString('\n')
numItems, _ := strconv.Atoi(strings.TrimSpace(line))
// 각 항목의 ID와 값 읽기
items := make([]Item, numItems)
for i := 0; i < numItems; i++ {
line, _ = reader.ReadString('\n')
id, _ := strconv.Atoi(strings.TrimSpace(line))
line, _ = reader.ReadString('\n')
value := strings.TrimSpace(line)
items[i] = Item{ID: id, Value: value}
}
// TODO: 지정된 용량으로 버퍼 채널 생성
// TODO: Producer를 실행하여 버퍼 채우기 (goroutine으로 실행하지 않음)
// TODO: Consumer를 실행하여 모든 항목 처리
// TODO: 소비된 각 결과를 별도 줄에 출력
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서9동시성 & OOP
Goroutines 기초Channels & 통신Buffered vs Unbuffered 채널Select 문sync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe 구조체 설계요약 - Worker Pool직접 연습해 보세요: 온라인 Go 컴파일러