插件窝 干货文章 Go语言singleflight库:如何避免并发情况下对同一资源的重复访问?

Go语言singleflight库:如何避免并发情况下对同一资源的重复访问?

singleflight resource Goroutine 资源 192    来源:    2025-03-16

在Go语言中,singleflight 是一个非常有用的库,用于在并发情况下避免对同一资源的重复访问。它通过将多个并发的请求合并为一个请求,从而减少对资源的重复访问,提高系统的性能和效率。

使用 singleflight 库的基本步骤

  1. 导入库: 首先,你需要导入 singleflight 包。

    import "golang.org/x/sync/singleflight"
    
  2. 创建 singleflight.Group: 你需要创建一个 singleflight.Group 实例。这个实例将用于管理并发请求。

    var group singleflight.Group
    
  3. 使用 Do 方法: 当你需要访问某个资源时,使用 group.Do 方法来确保同一时间只有一个请求在执行。Do 方法接受一个键(key)和一个函数(fn),函数 fn 是实际获取资源的逻辑。

    result, err, shared := group.Do("resourceKey", func() (interface{}, error) {
       // 这里是获取资源的逻辑
       return fetchResource()
    })
    
  • result 是获取到的资源。
  • err 是获取资源过程中可能发生的错误。
  • shared 是一个布尔值,表示这个结果是否被多个调用者共享。

示例代码

以下是一个完整的示例,展示了如何使用 singleflight 来避免对同一资源的重复访问。

package main

import (
    "fmt"
    "golang.org/x/sync/singleflight"
    "sync"
    "time"
)

var group singleflight.Group

func fetchResource() (interface{}, error) {
    // 模拟一个耗时的操作
    time.Sleep(2 * time.Second)
    return "resource data", nil
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            result, err, shared := group.Do("resourceKey", func() (interface{}, error) {
                return fetchResource()
            })
            if err != nil {
                fmt.Printf("Goroutine %d: Error fetching resource: %v\n", i, err)
            } else {
                fmt.Printf("Goroutine %d: Resource: %v, Shared: %v\n", i, result, shared)
            }
        }(i)
    }

    wg.Wait()
}

输出结果

在这个示例中,尽管有5个并发的goroutine尝试访问同一个资源,但由于使用了 singleflight,实际上只有一个goroutine会真正执行 fetchResource 函数,其他goroutine会等待并共享同一个结果。

Goroutine 0: Resource: resource data, Shared: true
Goroutine 1: Resource: resource data, Shared: true
Goroutine 2: Resource: resource data, Shared: true
Goroutine 3: Resource: resource data, Shared: true
Goroutine 4: Resource: resource data, Shared: true

总结

通过使用 singleflight 库,你可以有效地避免在并发情况下对同一资源的重复访问,从而减少不必要的资源消耗和系统负载。这对于高并发的系统尤其有用,特别是在处理缓存、数据库查询等场景时。