Sync.Once()
✅ Mục tiêu của sync.Once
sync.Once
sync.Once
được dùng để đảm bảo một đoạn mã chỉ được thực thi một lần duy nhất — dù có bao nhiêu goroutine gọi nó đồng thời.
📌 Use case phổ biến
Khởi tạo singleton
Đăng ký handlers hoặc middleware một lần
Thiết lập kết nối database / caching lần đầu tiên
🔧 Cách sử dụng sync.Once
sync.Once
var once sync.Once
func initialize() {
fmt.Println("Initializing...")
}
func main() {
for i := 0; i < 5; i++ {
go func() {
once.Do(initialize)
}()
}
time.Sleep(time.Second) // đợi goroutine chạy xong
}
✅ Kết quả in ra: duy nhất 1 lần
Initializing...
⚠️ Lưu ý quan trọng
1. once.Do(f)
sẽ gọi f()
một lần duy nhất trong suốt runtime.
once.Do(f)
sẽ gọi f()
một lần duy nhất trong suốt runtime.Dù bạn gọi
once.Do()
bao nhiêu lần hay từ bao nhiêu goroutine, thìf()
chỉ được thực thi duy nhất một lần.
2. Nếu f()
panic — sync.Once
coi như đã thực thi
f()
panic — sync.Once
coi như đã thực thivar once sync.Once
func panicFunc() {
fmt.Println("Panic here")
panic("oops")
}
func main() {
once.Do(panicFunc) // panic xảy ra ở đây
once.Do(func() {
fmt.Println("This will NOT run")
})
}
⚠️ Một khi
f()
panic, mọi lần gọi tiếp theo cũng sẽ bị bỏ qua.
✅ Ứng dụng thực tế — Singleton pattern
type Config struct {
DBHost string
}
var configInstance *Config
var once sync.Once
func GetConfig() *Config {
once.Do(func() {
fmt.Println("Loading config...")
configInstance = &Config{DBHost: "localhost"}
})
return configInstance
}
🧠 Tổng kết
Thuộc tính
Giá trị
Thread-safe
✅
Chỉ chạy một lần
✅
Không reset lại được
❌
Dùng trong init logic
✅
Nếu bạn muốn một cơ chế “chỉ chạy một lần” nhưng có khả năng reset hoặc nhiều lần tùy điều kiện, thì bạn sẽ cần dùng sync.Mutex
hoặc sync.OnceValue
(Go 1.22+).
Last updated