Go의 기본 문법을 넘어 실무에서 필요한 고급 동시성 패턴을 다룹니다. Worker Pool, Fan-out/Fan-in, Context를 활용한 취소 처리, 에러 그룹 등 프로덕션 레벨 Go 코드를 작성하는 방법을 배웁니다.
Beyond Go basics, this covers advanced concurrency patterns needed in practice. Learn to write production-level Go code with Worker Pool, Fan-out/Fan-in, cancellation with Context, and error groups.
Worker Pool 패턴 Worker Pool Pattern
대량의 작업을 효율적으로 처리하기 위해 고정된 수의 워커 고루틴을 사용합니다. 리소스 사용을 제한하면서도 병렬 처리의 이점을 얻을 수 있습니다.
Use a fixed number of worker goroutines to efficiently process large amounts of work. You get the benefits of parallel processing while limiting resource usage.
var wg sync.WaitGroup
// 워커 생성
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for job := range jobs {
results <- process(job)
}
}(i)
}
wg.Wait()
close(results)
}
var wg sync.WaitGroup
// Create workers
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for job := range jobs {
results <- process(job)
}
}(i)
}
wg.Wait()
close(results)
}
Context로 취소 처리 Cancellation with Context
context.Context는 Go에서 취소 신호, 타임아웃, 값 전달을 위한 표준 방법입니다.
HTTP 요청, 데이터베이스 쿼리 등 모든 I/O 작업에 사용해야 합니다.
context.Context is Go's standard way to carry cancellation signals, timeouts, and
values.
It should be used for all I/O operations like HTTP requests and database queries.
ctx, cancel := context.WithTimeout(
context.Background(),
5*time.Second,
)
defer cancel()
// HTTP 요청에 컨텍스트 사용
req, _ := http.NewRequestWithContext(
ctx, "GET", url, nil,
)
resp, err := client.Do(req)
// 취소 확인
select {
case <-ctx.Done():
return ctx.Err()
case result := <-resultCh:
return result
}
ctx, cancel := context.WithTimeout(
context.Background(),
5*time.Second,
)
defer cancel()
// Use context for HTTP request
req, _ := http.NewRequestWithContext(
ctx, "GET", url, nil,
)
resp, err := client.Do(req)
// Check for cancellation
select {
case <-ctx.Done():
return ctx.Err()
case result := <-resultCh:
return result
}
📊 Context 종류 📊 Context Types
- context.Background(): 최상위 컨텍스트, main에서 시작
- context.Background(): Top-level context, starts from main
- context.WithCancel: 수동 취소 가능
- context.WithCancel: Manual cancellation
- context.WithTimeout: 지정 시간 후 자동 취소
- context.WithTimeout: Auto-cancel after duration
- context.WithDeadline: 특정 시점에 자동 취소
- context.WithDeadline: Auto-cancel at specific time
에러 그룹 (errgroup) Error Groups (errgroup)
여러 고루틴에서 발생하는 에러를 깔끔하게 처리하려면 golang.org/x/sync/errgroup을 사용합니다.
Use golang.org/x/sync/errgroup to cleanly handle errors from multiple goroutines.
func fetchAll(urls []string) error {
g, ctx := errgroup.WithContext(context.Background())
for _, url := range urls {
url := url // 클로저용 복사
g.Go(func() error {
return fetch(ctx, url)
})
}
// 모든 고루틴 완료 대기, 첫 에러 반환
return g.Wait()
}
func fetchAll(urls []string) error {
g, ctx := errgroup.WithContext(context.Background())
for _, url := range urls {
url := url // Copy for closure
g.Go(func() error {
return fetch(ctx, url)
})
}
// Wait for all goroutines, return first error
return g.Wait()
}
Select 패턴 활용 Select Pattern Usage
select {
case msg := <-msgCh:
fmt.Println("메시지:", msg)
case err := <-errCh:
return err
case <-time.After(10 * time.Second):
return errors.New("타임아웃")
case <-ctx.Done():
return ctx.Err()
}
select {
case msg := <-msgCh:
fmt.Println("Message:", msg)
case err := <-errCh:
return err
case <-time.After(10 * time.Second):
return errors.New("timeout")
case <-ctx.Done():
return ctx.Err()
}
테이블 기반 테스트 Table-Driven Tests
Go에서 권장하는 테스트 작성 패턴입니다. 여러 케이스를 깔끔하게 정리할 수 있습니다.
This is Go's recommended testing pattern. It organizes multiple cases cleanly.
tests := []struct {
name string
a, b int
want int
}{
{"양수", 1, 2, 3},
{"음수", -1, -2, -3},
{"영", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add() = %v, want %v", got, tt.want)
}
})
}
}
tests := []struct {
name string
a, b int
want int
}{
{"positive", 1, 2, 3},
{"negative", -1, -2, -3},
{"zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add() = %v, want %v", got, tt.want)
}
})
}
}
💡 Go 동시성 타자 연습 팁 💡 Go Concurrency Typing Tips
go func(), chan, select, ctx.Done() 패턴을 자주
타이핑해보세요.
동시성 코드는 복잡해 보이지만, 패턴을 체화하면 빠르게 작성할 수 있습니다.
Practice typing go func(), chan, select,
ctx.Done() patterns often.
Concurrent code looks complex, but once you internalize the patterns, you can write them
quickly.
⚠️ 고루틴 누수 방지 ⚠️ Preventing Goroutine Leaks
고루틴이 영원히 블록되면 메모리 누수가 발생합니다.
항상 context를 사용하거나 채널을 닫아 고루틴이 종료될 수 있게 하세요.
Goroutines that block forever cause memory leaks.
Always use context or close channels to ensure goroutines can exit.
