Golang 基本同步原语sync.Onece

sync.Once 是 Go 语言中一个简单但强大的同步原语,用于确保某个操作在并发场景下只执行一次。它常用于延迟初始化、单例模式、全局配置加载等场景

基本用法

sync.Once 的核心方法是 Do(f func()),传入的函数 f 只会执行一次,即使多个 goroutine 同时调用 Do

内部实现原理

sync.Once 的源码非常简洁,其核心是通过一个 uint32 类型的原子标志位(done)和一个互斥锁(m)实现的:

package sync

import (
    "sync/atomic"
)

type Once struct {
    done uint32
    m    Mutex
}

func (o *Once) Do(f func()) {
    if atomic.LoadUint32(&o.done) == 0 {
        o.doSlow(f)
    }
}

func (o *Once) doSlow(f func()) {
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}

使用 done 标记是否已经初始化,使用锁 m Mutex 实现线程安全。

image-20250129005509047

image-20250129005808164

使用案例

使用单例模式,只读取一次配置文件,完成程序初始化

config.go
package config

import (
	"fmt"
	"os"
	"sync"

	"github.com/pelletier/go-toml"
)

// Config 代表配置结构
type Config struct {
	App AppConfig `toml:"app"`
}

// AppConfig 表示 [app] 下的配置
type AppConfig struct {
	Port    int    `toml:"port"`
	AppName string `toml:"app_name"`
}

var (
	instance *Config
	once     sync.Once
)

// LoadConfig 加载 TOML 配置文件
func LoadConfig(filePath string) (*Config, error) {
	var err error
	once.Do(func() {
		fmt.Println("Loading TOML configuration...") // 只会执行一次
		instance, err = loadConfigFromFile(filePath)
	})
	if err != nil {
		return nil, err
	}
	return instance, nil
}

// loadConfigFromFile 从文件中解析 TOML 配置
func loadConfigFromFile(filePath string) (*Config, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	decoder := toml.NewDecoder(file)
	config := &Config{}
	if err := decoder.Decode(config); err != nil {
		return nil, err
	}
	return config, nil
}

config.toml
[app]
app_name = "MyApp"
port = 8080

main.go
package main

import (
	"awesomeProject/config"
	"fmt"
	"log"
)

func main() {
	// 假设配置文件路径为 config.toml
	filePath := "config/config.toml"

	cfg, err := config.LoadConfig(filePath)
	if err != nil {
		log.Fatalf("Failed to load config: %v", err)
	}
	fmt.Printf("App Name: %s, Port: %d\n", cfg.App.AppName, cfg.App.Port)
}

适用场景

image-20250129005649018