sync.Once: Go 동시성 문제 해결의 핵심

카테고리

프로그래밍/소프트웨어 개발

서브카테고리

개발 툴

대상자

Go 개발자 (1~2년 경력, goroutine 및 mutex 이해 필요)

난이도: 중간 (기본 개념 이해 후 활용 팁 제공)

핵심 요약

  • sync.Oncesync 패키지의 Do(f func()) 메서드를 통해 동시성 환경에서 특정 함수를 정확히 한 번 실행하는 도구.
  • 사용 사례: 싱글톤 초기화 (global logger), 지연 로딩 (database pool), 중복 작업 방지 등.
  • 성능: 첫 번째 실행 시 Mutex 사용, 이후에는 atomic.LoadUint32경량한 접근 가능.

섹션별 세부 요약

1. 소개

  • sync.Once중복 실행 방지자원 낭비 최소화를 위한 Go의 핵심 도구.
  • 사용 예시: config 파일 로딩, DB 연결 초기화, 싱글톤 생성 등.
  • 장점: sync.Mutex보다 간단, init()보다 유연한 실행 시점 제어.

2. API 및 사용법

  • 메서드: func (o *Once) Do(f func())

- f: 입력/출력 없이 실행되는 함수.

- 동작: Do 첫 호출 시 f 실행, 이후 호출 시 무시.

  • 예제 코드:

```go

var once sync.Once

once.Do(func() { fmt.Println("실행됨") })

```

3. 내부 구현 원리

  • 구조체:

```go

type Once struct {

done uint32 // 0: 미실행, 1: 완료

m Mutex // 첫 번째 실행 보호

}

```

  • 동작 흐름:
  1. atomic.LoadUint32done 확인 (0일 경우만 Mutex 잠금).
  2. done이 0일 경우 f() 실행 후 atomic.StoreUint32done 1로 업데이트.
  3. 이후 호출은 done 체크 후 즉시 종료.

4. 성능 및 안정성

  • 첫 실행: Mutex 잠금으로 동기화 보장.
  • 이후 실행: atomic.LoadUint32경량한 접근.
  • 안정성: atomicMutex 조합으로 경쟁 조건 방지.

5. 실제 사용 사례

  • 싱글톤 초기화:

```go

var config *Config

var once sync.Once

func GetConfig() *Config {

once.Do(func() { config = &Config{...} })

return config

}

```

  • DB 연결 풀 생성:

```go

var db *sql.DB

func GetDB() *sql.DB {

once.Do(func() { db, _ = sql.Open(...) })

return db

}

```

결론

  • 실무 팁: sync.Once는 초기화 작업에 최적화되어 있으며, sync.Mutex 또는 init()보다 간결하고 효율적.
  • 주의사항: Do 함수 내부에서 panic 발생 시, 다른 goroutine에 영향을 줄 수 있으므로 예외 처리 필수.
  • 핵심 원칙: "한 번만 실행"이 필요한 작업에 sync.Once 사용, 중복 작업 방지 및 자원 최적화를 목표로.