当前位置:首页 > Go > 正文

Go语言并发利器:sync.Once详解(如何用sync.Once实现只执行一次的代码)

Go语言 的并发编程中,我们经常会遇到这样的需求:某个初始化操作(比如配置加载、数据库连接、单例创建等)只需要在整个程序生命周期中执行一次,即使有多个 Goroutine 同时尝试执行它。这时候,sync.Once 就派上用场了!

Go语言并发利器:sync.Once详解(如何用sync.Once实现只执行一次的代码) Go语言 sync.Once 单例模式 并发安全 第1张

什么是 sync.Once?

sync.Once 是 Go 标准库 sync 包中的一个结构体,它提供了一种机制,确保某段代码在多线程(Goroutine)环境下仅被执行一次。它是 并发安全 的,无需额外加锁。

为什么需要 sync.Once?

想象一下,你正在开发一个 Web 服务,需要在启动时加载配置文件。如果多个 Goroutine 同时启动并尝试加载配置,可能会导致:

  • 重复加载,浪费资源
  • 竞态条件(Race Condition)
  • 程序行为不一致

使用 sync.Once 可以完美解决这些问题,确保初始化逻辑只运行一次。

sync.Once 基本用法

使用 sync.Once 非常简单,只需两步:

  1. 声明一个 sync.Once 类型的变量
  2. 调用其 Do(func()) 方法,传入要只执行一次的函数

下面是一个经典示例——实现 单例模式

package mainimport (    "fmt"    "sync")// Singleton 单例结构体type Singleton struct {    data string}var (    instance *Singleton    once     sync.Once)// GetInstance 获取单例实例func GetInstance() *Singleton {    once.Do(func() {        fmt.Println("Creating singleton instance...")        instance = &Singleton{data: "I am singleton!"}    })    return instance}func main() {    // 模拟多个 Goroutine 同时获取实例    var wg sync.WaitGroup    for i := 0; i < 5; i++ {        wg.Add(1)        go func(id int) {            defer wg.Done()            s := GetInstance()            fmt.Printf("Goroutine %d: %s\n", id, s.data)        }(i)    }    wg.Wait()}

运行结果(顺序可能不同,但“Creating singleton instance...”只打印一次):

Creating singleton instance...Goroutine 3: I am singleton!Goroutine 0: I am singleton!Goroutine 1: I am singleton!Goroutine 2: I am singleton!Goroutine 4: I am singleton!

可以看到,尽管有 5 个 Goroutine 同时调用 GetInstance(),但初始化代码(once.Do 中的匿名函数)只执行了一次。这就是 sync.Once 的魔力!

sync.Once 的关键特性

  • 并发安全:内部使用原子操作和互斥锁保证线程安全
  • 高效:一旦执行完成,后续调用 Do 几乎无开销
  • 幂等性:多次调用 Do 不会重复执行函数

常见使用场景

除了实现 单例模式sync.Once 还适用于:

  • 一次性初始化日志系统
  • 加载全局配置文件
  • 建立数据库连接池
  • 注册信号处理函数

注意事项

1. sync.Once 不能重置。一旦执行过,就永远不会再执行。

2. 如果 Do 中的函数 panic,sync.Once 会认为“已执行”,后续调用不会再次执行。因此建议在函数内处理 panic。

once.Do(func() {    defer func() {        if r := recover(); r != nil {            log.Printf("Recovering from panic in once.Do: %v", r)        }    }()    // 可能 panic 的初始化代码})

总结

Go语言 开发中,sync.Once 是实现 并发安全 的“只执行一次”逻辑的最佳工具。它简洁、高效、可靠,特别适合用于 单例模式 和各种初始化场景。掌握它,能让你的并发程序更加健壮和高效!

记住这四个关键词:Go语言sync.Once单例模式并发安全 —— 它们是你构建高性能 Go 应用的重要基石。