Contents

go sync

go sync 包

1、sync.WaitGroup(等待组)

用途:等待一组 Goroutine 全部执行完成。常用于主程序等待后台任务结束,或者在批量处理任务时确保所有子任务完成后再进行下一步。

  • 核心方法

    • Add(delta int): 增加计数(通常在启动 goroutine 前调用)。
    • Done(): 计数减 1(通常在 goroutine 结束时调用,等价于 Add(-1))。
    • Wait(): 阻塞直到计数归零。
    var wg sync.WaitGroup
    urls := []string{"url1", "url2", "url3"}
    
    for _, url := range urls {
        wg.Add(1) // 计数 +1
        go func(u string) {
            defer wg.Done() // 任务完成,计数 -1
            fetch(u)
        }(url)
    }
    
    wg.Wait() // 阻塞,直到所有 fetch 完成
    fmt.Println("All fetches done")
    

2、sync.Once (单次执行)

用途:确保某段代码(通常是初始化逻辑)在整个程序生命周期中只执行一次。它是实现线程安全单例模式(Singleton)的最简单方式。

  • 核心方法
    • Do(f func()): 如果这是第一次调用 Do,则执行函数 f;否则直接返回。
  • 代码示例
var (
    instance *Config
    once     sync.Once
)

func GetConfig() *Config {
    once.Do(func() {
        // 这里的代码只会执行一次,即使有多个 goroutine 同时调用
        instance = loadConfigFromDisk() 
    })
    return instance
}

3、 sync.Map (并发安全的 Map)

用途:专为读多写少键空间不重叠(每个 goroutine 操作不同的 key)的场景设计的并发安全 Map。

  • 特点
    • 内部采用分离读取和写入路径的技术(类似读写锁但优化更好),在特定场景下性能远超 map + Mutex
    • 不适用于写操作频繁且键空间高度重叠的场景(此时 map + Mutex 可能更快)。
    • 不支持范围遍历时的动态修改(需小心处理)。
  • 核心方法
    • Load(key): 读取。
    • Store(key, value): 写入。
    • LoadOrStore(key, value): 如果存在则返回旧值,否则存入新值。
    • Delete(key): 删除。
    • Range(f func(key, value interface{}) bool): 遍历。
var m sync.Map
m.Store("userId", 1001)

val, ok := m.Load("userId")
if ok {
    fmt.Println(val)
}

4、sync.Mutex & sync.RWMutex

虽然前面详细讲过,但在“常用”列表中它们依然是基石:

  • sync.Mutex: 互斥锁,通用性强。
  • sync.RWMutex: 读写锁,适合读多写少。