# 1. 简介

在有些资源初始化成本很高,甚至在某些代码路径未触发根本没有必要初始化,可以将对象的创建、配置等耗时操作推迟到真正需要使用时才执行。

# 2. 延迟初始化实现

# 2.1 sync.Once

sync.Once 是Go标准库提供的线程安全初始化工具,确保初始化代码只执行一次:

var (
    resource *MyResource  // 需要延迟初始化的资源
    once     sync.Once    // 控制初始化的同步原语
)

func getResource() *MyResource {
    once.Do(func() {
        resource = &MyResource{
            // 初始化代码
        }
    })
    return resource
}

1
2
3
4
5
6
7
8
9
10
11
12
13

特点:

  • 线程安全,适合并发场景
  • 初始化逻辑与业务代码耦合
  • 需要额外定义全局变量

# 2.2 sync.OnceValue (Go 1.21+)

Go 1.21引入了更简洁的sync.OnceValue,适合返回单个值的场景:

var getResource = sync.OnceValue(func() *MyResource {
    return &MyResource{
        // 初始化代码
    }
})

// 使用示例
func main() {
    res := getResource()  // 第一次调用时初始化
    _ = getResource()     // 后续调用直接返回缓存值

1
2
3
4
5
6
7
8
9
10

# 2.3 错误处理方案:sync.OnceValues

当初始化可能返回错误时,使用sync.OnceValues:

var getConfig = sync.OnceValues(func() (*Config, error) {
    return loadConfig("config.yml")
})

func main() {
    config, err := getConfig()
    if err != nil {
        log.Fatal("加载配置失败:", err)
    }
    // 使用配置...
}

1
2
3
4
5
6
7
8
9
10
11

# 3. 总结

在以下场景中适合使用延迟初始化:

  • 资源初始化成本非常高。
  • 为了提高启动性能和内存效率。
  • 当并非所有的资源都需要在运行时立即使用,甚至根本不需要使用。