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

go sync.oncevalue一个单例的更简实现

我来为你详细解析 `sync.OnceValue` —— Go 1.21 引入的并发安全初始化工具。

核心概念

`sync.OnceValue` 是 Go 1.21 新增的泛型函数,用于惰性且线程安全地初始化一个值:

```go
func OnceValue[T any](f func() T) func() T
```

它返回一个闭包,确保 `f` 只执行一次,后续调用直接返回缓存结果。

---

基础用法

```go
package main

import (
"fmt"
"sync"
"time"
)

func main() {
// 定义一个昂贵的初始化操作
initConfig := sync.OnceValue(func() map[string]string {
fmt.Println("⚙️ 正在加载配置... (只执行一次)")
time.Sleep(100 * time.Millisecond) // 模拟耗时操作

return map[string]string{
"db_host": "localhost",
"db_port": "5432",
"api_key": "secret-123",
}
})

// 并发多次获取配置
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()

config := initConfig() // 并发安全调用
fmt.Printf("Goroutine %d: %v\n", id, config["db_host"])
}(i)
}

wg.Wait()

// 再次调用,直接返回缓存值
cfg := initConfig()
fmt.Printf("Final call: %v\n", cfg)
}
```

输出:

```
⚙️ 正在加载配置... (只执行一次)
Goroutine 2: localhost
Goroutine 0: localhost
Goroutine 4: localhost
Goroutine 1: localhost
Goroutine 3: localhost
Final call: map[api_key:secret-123 db_host:localhost db_port:5432]
```

---

与 `sync.Once` 的对比

特性 `sync.Once` `sync.OnceValue`
代码量 需要额外变量存储结果 自动缓存返回值
类型安全 需手动类型断言 泛型支持,类型安全
复用性 封装较繁琐 返回闭包,可传递
错误处理 需手动处理 需配合 `OnceValue` + `error` 模式

传统 `sync.Once` 写法

```go
var (
once sync.Once
config map[string]string
)

func GetConfig() map[string]string {
once.Do(func() {
config = loadConfig() // 需外部变量存储
})
return config
}
```

`OnceValue` 写法(更简洁)

```go
var getConfig = sync.OnceValue(func() map[string]string {
return loadConfig()
})

// 使用:config := getConfig()
```

---

高级场景

1. 带错误处理的初始化(`OnceValues`)

```go
// Go 1.21 也提供了 OnceValues 用于多返回值
var initDB = sync.OnceValues(func() (*sql.DB, error) {
db, err := sql.Open("postgres", dsn)
if err != nil {
return nil, err
}
return db, db.Ping()
})

// 使用
db, err := initDB()
```

2. 单例模式实现

```go
type Service struct {
client *http.Client
}

var getService = sync.OnceValue(func() *Service {
return &Service{
client: &http.Client{Timeout: 30 * time.Second},
}
})

func Instance() *Service {
return getService()
}
```

3. 延迟计算 + 缓存

```go
// 计算斐波那契数列(带缓存)
var fib = sync.OnceValue(func() []int {
fmt.Println("计算斐波那契数列...")
seq := make([]int, 50)
seq[0], seq[1] = 0, 1
for i := 2; i < 50; i++ {
seq[i] = seq[i-1] + seq[i-2]
}
return seq
})

// 多次调用,只计算一次
fmt.Println(fib()[10]) // 55
fmt.Println(fib()[20]) // 6765
```

---

关键特性总结

1. 线程安全:内部使用 `sync.Once`,保证并发安全
2. 惰性求值:首次调用时才执行初始化
3. 结果缓存:执行结果永久缓存,后续调用零开销
4. 泛型支持:编译期类型检查,无需类型断言
5. 不可重置:一旦初始化完成,无法重新执行(如需重置需重新创建)

---

适用场景

- ✅ 全局配置加载
- ✅ 数据库连接池初始化
- ✅ 单例服务对象
- ✅ 昂贵的计算结果缓存
- ✅ 资源预加载(图片、模板等)

`sync.OnceValue` 让 Go 的惰性初始化代码更加简洁、类型安全,是替代传统 `sync.Once` + 全局变量的现代最佳实践。

http://www.jsqmd.com/news/343051/

相关文章:

  • 1.10 CDN缓存
  • 86_Spring AI 干货笔记之 Chroma 向量存储
  • 检测性能直登顶!Mamba+YOLO优势互补,碾压所有传统YOLO!
  • 26. Mipmap
  • 大数据毕设项目:基于python+Hadoop的国家气象降雨量大数据分析系统(源码+文档,讲解、调试运行,定制等)
  • 顾比均线、顾比倒数线与趋势线相结合,加上仓位管理,可构成一套完整的趋势型交易系统 - Leone
  • 【无人机协同】基于matlab动态环境下多无人机系统的协同路径规划与防撞附Matlab代码
  • 【计算机毕业设计案例】基于Hadoop的某篮球队各个球员数据分析系统的设计与实现(程序+文档+讲解+定制)
  • 为什么新手总觉得 Modbus 很难?
  • 咖啡豆烘焙机厂家哪家实用性强?2026年榜单这几家靠谱企业值得关注! - 海棠依旧大
  • 排查某个软件是否安装,某个端口是否占用
  • 花 Opus 的钱买到 Sonnet?一行 Python 代码揭穿 API 服务商的“降本增效”骗局
  • 大数据BI工具的增强分析能力测评
  • 85_Spring AI 干货笔记之 Apache Cassandra 向量存储
  • 2026年2月中国境外券商投行机构推荐:看这5家公司就对了 - Top品牌推荐
  • 深入解析:【MySQL】数据库备份与恢复
  • 苹果 iPhone 14 Pro Max 高质量深度解析|配色外观|核心参数|屏幕与影像|续航充电|官方维修手册|二手验机清单
  • 【毕业设计】基于python+Hadoop的国家气象降雨量大数据分析系统(源码+文档+远程调试,全bao定制等)
  • 苹果 iPhone 15 高质量介绍:参数解析|体验要点|验机清单|维修手册重点
  • ubuntu卸载包
  • 程序员如何从 0 到 1 自己开发一个 AI Agent?
  • 03. PyTorch的使用
  • day76(2.4)——leetcode面试经典150
  • 一个 SpringBoot 项目能处理多少请求?我终于悟了
  • 企业级 Agent 在 K8s 上的运行模型
  • 【计算机毕业设计案例】基于python+Hadoop的国家气象降雨量大数据分析系统基于hadoop的气象数据分析与可视化系统(程序+文档+讲解+定制)
  • SpringCloud从入门到上天:Nacos做微服务注册中心
  • 来自 Nimbus-7 SMMR 和 DMSP SSM/I-SSMIS 被动微波数据的海冰浓度 V002
  • 高校物业维修管理微信小程序的设计和实现
  • MySQL 5.7 转 Oracle 实习生核心注意事项(企业常见场景)