PHpullh
학습 라이브러리/Go/고루틴 & WaitGroup

GO · 고루틴/채널

고루틴 & WaitGroup

Go의 경량 스레드인 고루틴과 동기화 도구 WaitGroup으로 병렬 처리를 구현합니다.

고루틴/채널중급goroutineWaitGroupMutexRWMutexsync

핵심 설명

Go의 경량 스레드인 고루틴과 동기화 도구 WaitGroup으로 병렬 처리를 구현합니다.

Go code

package main

import (
	"fmt"
	"sync"
	"time"
)

func worker(id int, wg *sync.WaitGroup) {
	defer wg.Done()   // 완료 시 카운터 감소
	fmt.Printf("worker %d 시작
", id)
	time.Sleep(time.Duration(id) * 100 * time.Millisecond)
	fmt.Printf("worker %d 완료
", id)
}

// Mutex로 경쟁 조건 방지
type SafeCounter struct {
	mu sync.Mutex
	v  map[string]int
}

func (c *SafeCounter) Inc(key string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.v[key]++
}

func (c *SafeCounter) Value(key string) int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.v[key]
}

func main() {
	// WaitGroup 기본 패턴
	var wg sync.WaitGroup

	for i := 1; i <= 5; i++ {
		wg.Add(1)
		go worker(i, &wg)
	}
	wg.Wait()
	fmt.Println("모든 worker 완료")

	// RWMutex — 읽기는 동시, 쓰기는 독점
	var rwmu sync.RWMutex
	data := make(map[string]string)

	// 쓰기
	rwmu.Lock()
	data["key"] = "value"
	rwmu.Unlock()

	// 읽기 (여러 고루틴 동시 가능)
	rwmu.RLock()
	fmt.Println(data["key"])
	rwmu.RUnlock()

	// SafeCounter 사용
	counter := SafeCounter{v: make(map[string]int)}
	for i := 0; i < 100; i++ {
		go counter.Inc("key")
	}
	time.Sleep(100 * time.Millisecond)
	fmt.Println("카운트:", counter.Value("key"))
}

학습 팁

go run -race main.go로 race condition을 감지할 수 있습니다. 개발 중에 습관적으로 실행하세요.

주의할 점

wg.Add(1)은 고루틴 시작 전에 호출해야 합니다. 고루틴 내부에서 호출하면 WaitGroup이 이미 0이 될 수 있습니다.

자주 묻는 질문

고루틴 & WaitGroup란 무엇인가요?

Go의 경량 스레드인 고루틴과 동기화 도구 WaitGroup으로 병렬 처리를 구현합니다.

고루틴 & WaitGroup 학습 시 주의할 점은 무엇인가요?

wg.Add(1) 은 고루틴 시작 전에 호출해야 합니다. 고루틴 내부에서 호출하면 WaitGroup이 이미 0이 될 수 있습니다.