PHpullh
학습 라이브러리/Go/sync.Once & atomic 패키지

GO · 고루틴/채널

sync.Once & atomic 패키지

한 번만 실행되는 초기화와 원자적 연산으로 동시성을 안전하게 처리합니다.

고루틴/채널고급sync.OnceatomicsingletonCAS동시성

핵심 설명

한 번만 실행되는 초기화와 원자적 연산으로 동시성을 안전하게 처리합니다.

Go code

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

// sync.Once — 딱 한 번만 실행 (lazy singleton)
type Database struct {
	conn string
}

var (
	db   *Database
	once sync.Once
)

func GetDB() *Database {
	once.Do(func() {
		fmt.Println("DB 초기화 (한 번만)")
		db = &Database{conn: "postgres://localhost:5432/mydb"}
	})
	return db
}

// atomic — 락 없는 원자적 연산
type AtomicCounter struct {
	value int64
}

func (c *AtomicCounter) Inc() {
	atomic.AddInt64(&c.value, 1)
}

func (c *AtomicCounter) Load() int64 {
	return atomic.LoadInt64(&c.value)
}

func (c *AtomicCounter) CompareAndSwap(old, new int64) bool {
	return atomic.CompareAndSwapInt64(&c.value, old, new)
}

func main() {
	// sync.Once 테스트
	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			db := GetDB()
			fmt.Println("사용:", db.conn)
		}()
	}
	wg.Wait()

	// atomic counter
	counter := &AtomicCounter{}
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			counter.Inc()
		}()
	}
	wg.Wait()
	fmt.Println("최종 카운트:", counter.Load()) // 1000

	// CAS (Compare-And-Swap) 패턴
	ok := counter.CompareAndSwap(1000, 0)
	fmt.Println("CAS 성공:", ok, "값:", counter.Load())
}

학습 팁

sync.Once는 초기화 함수가 패닉을 발생시켜도 다시 호출되지 않습니다. 패닉에서 복구해도 초기화는 "완료된" 상태로 남습니다.

주의할 점

atomic 연산은 단일 변수에 대해서만 원자적입니다. 여러 변수를 함께 업데이트해야 하면 Mutex를 사용하세요.

자주 묻는 질문

sync.Once & atomic 패키지란 무엇인가요?

한 번만 실행되는 초기화와 원자적 연산으로 동시성을 안전하게 처리합니다.

sync.Once & atomic 패키지 학습 시 주의할 점은 무엇인가요?

atomic 연산은 단일 변수에 대해서만 원자적입니다. 여러 변수를 함께 업데이트해야 하면 Mutex를 사용하세요.