You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中并发调用时如何实现共享数据仅单次获取?

解决方案:并发共享资源加载,避免重复请求

要实现多个goroutine共享同一次资源加载的结果,核心是通过互斥锁+条件变量同步加载状态,让后续请求等待首次加载完成后直接复用结果。以下是具体实现:

核心实现代码

import (
    "math/rand"
    "sync"
    "time"
    "fmt"
)

type ConfigLoader struct {
    mu     sync.Mutex
    cond   *sync.Cond
    config int64
    loaded bool
    // 可选:添加过期时间支持配置自动刷新
    // expireAt time.Time
}

func NewConfigLoader() *ConfigLoader {
    cl := &ConfigLoader{}
    cl.cond = sync.NewCond(&cl.mu)
    return cl
}

// GetConfig 获取配置,若未加载则等待加载完成
func (cl *ConfigLoader) GetConfig() int64 {
    cl.mu.Lock()
    defer cl.mu.Unlock()

    // 可选:检查配置是否过期,过期则标记为未加载
    // if cl.loaded && time.Now().After(cl.expireAt) {
    //     cl.loaded = false
    // }

    // 循环等待直到配置加载完成
    for !cl.loaded {
        cl.cond.Wait()
    }
    return cl.config
}

// LoadConfig 加载配置,仅当配置未加载时执行
func (cl *ConfigLoader) LoadConfig() {
    cl.mu.Lock()
    if cl.loaded {
        cl.mu.Unlock()
        return
    }
    cl.mu.Unlock()

    // 模拟从S3获取配置的耗时操作
    rand.Seed(time.Now().UnixNano())
    config := rand.Int63()

    cl.mu.Lock()
    cl.config = config
    cl.loaded = true
    // 可选:设置过期时间
    // cl.expireAt = time.Now().Add(5 * time.Minute)
    // 唤醒所有等待的goroutine
    cl.cond.Broadcast()
    cl.mu.Unlock()
}

// Refresh 主动刷新配置,触发重新加载
func (cl *ConfigLoader) Refresh() {
    cl.mu.Lock()
    cl.loaded = false
    cl.mu.Unlock()
    cl.LoadConfig()
}

func main() {
    loader := NewConfigLoader()

    var wg sync.WaitGroup
    wg.Add(2)
    // 并发启动两个请求
    go func() {
        defer wg.Done()
        fmt.Println("#1 start")
        loader.LoadConfig()
        fmt.Printf("#1 result %d\n", loader.GetConfig())
    }()
    go func() {
        defer wg.Done()
        fmt.Println("#2 start")
        loader.LoadConfig()
        fmt.Printf("#2 result %d\n", loader.GetConfig())
    }()
    wg.Wait()

    // 后续请求,刷新配置后获取新结果
    fmt.Println("#3 start")
    loader.Refresh()
    fmt.Printf("#3 result %d\n", loader.GetConfig())
}

关键逻辑说明

  1. 状态保护:用sync.Mutex锁保护loaded状态和config结果,确保并发下状态修改的原子性。
  2. 等待机制:通过sync.Cond条件变量,让未抢到加载权的goroutine进入等待状态,避免重复发起加载请求。
  3. 结果共享:首次加载完成后,调用Broadcast()唤醒所有等待的goroutine,它们会直接获取已加载的配置结果。
  4. 可扩展性:若需要支持配置过期刷新,只需在GetConfig中添加过期检查,标记loaded为false即可触发重新加载,并发请求仍会共享同一次刷新的结果。

输出效果

运行上述代码会得到符合预期的结果:

#2 start
#1 start
#1 result 5577006791947779410
#2 result 5577006791947779410
#3 start
#3 result 6129484611666145821

内容的提问来源于stack exchange,提问作者Stéphane Bruckert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:18:28