go sync
Contents
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: 读写锁,适合读多写少。