개요

Go의 sync 패키지는 고루틴 간 동시성 제어를 위해 사용됩니다. 주로 멀티 쓰레드 환경에서 데이터 경쟁을 방지하고 성능을 최적화하는 데 사용됩니다.

sync.Mutex (뮤텍스 - Mutual Exclusion)

sync.Mutex한 번에 하나의 고루틴만 특정 코드 블록을 실행할 수 있도록 하는 상호 배제(뮤텍스, mutual exclusion) 락입니다.

package main

import (
    "fmt"
    "sync"
)

var (
    counter int
    mutex   sync.Mutex
)

func increment(wg *sync.WaitGroup) {
    defer wg.Done()
    
    mutex.Lock()   // 락 획득
    counter++      // 공유 데이터 변경
    mutex.Unlock() // 락 해제
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
    fmt.Println("Final Counter:", counter) // 10이 보장됨
}

sync.RWMutex (읽기/쓰기 분리 락)

package main

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

var (
    rwMutex sync.RWMutex
    data    int
)

func readData(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    rwMutex.RLock() // 읽기 락 (여러 고루틴이 동시에 실행 가능)
    fmt.Printf("Reader %d: Read data = %d\\n", id, data)
    time.Sleep(time.Millisecond * 100)
    rwMutex.RUnlock()
}

func writeData(wg *sync.WaitGroup) {
    defer wg.Done()
    rwMutex.Lock() // 쓰기 락 (다른 모든 고루틴이 차단됨)
    data++
    fmt.Println("Writer: Updated data =", data)
    time.Sleep(time.Millisecond * 200)
    rwMutex.Unlock()
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go readData(i, &wg)
    }

    wg.Add(1)
    go writeData(&wg)

    wg.Wait()
}

sync.WaitGroup (고루틴 완료 대기)

sync.WaitGroup고루틴이 종료될 때까지 기다리는 역할을 합니다.

package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 작업 완료 시 WaitGroup 카운트 감소
    fmt.Printf("Worker %d starting\\n", id)
    time.Sleep(time.Second) // 작업 수행
    fmt.Printf("Worker %d done\\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1) // WaitGroup 카운트 증가
        go worker(i, &wg)
    }

    wg.Wait() // 모든 고루틴이 완료될 때까지 대기
    fmt.Println("All workers done")
}