同时调用应该只获取一次数据



我遇到了一个不寻常的场景,其中:

  • 一个外部工具同时调用我的API的多个端点
  • 所有端点都依赖于S3上某个地方托管的相同配置文件

这是有效的,但它会同时提取同一个配置文件多次,而只能提取一次。为了进行实验,我在这里有一个最小版本https://go.dev/play/p/Nx-kidmprQx它返回随机int,而不是执行HTTP调用。

目前打印:

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

但我希望前两个调用返回相同的值,因为它们是同时进行的:

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

我很难想象解决这个问题的办法。多个goroutine应该等待一个结果这一事实令人困惑。怎么能做到呢?

您可以从golang.org/x/sync/singleflight使用Group.Do实现

// Do executes and returns the results of the given function, making
// sure that only one execution is in-flight for a given key at a
// time. If a duplicate comes in, the duplicate caller waits for the
// original to complete and receives the same results.
// The return value shared indicates whether v was given to multiple callers.

修改您的示例以将功能的同步部分与通道操作分离:

func httpCall(run int) int {
fmt.Printf("#%d startn", run)
time.Sleep(time.Second)
return rand.Int()
}

您可以使用一个简单的包装器函数来处理singleflight.Group调用:

go func() {
res, _, _ := g.Do("httpCall", func() (any, error) {
return httpCall(1), nil
})
done <- res.(int)
}()

请参阅https://go.dev/play/p/ET0jNKEyg1_B

最新更新