我遇到了一个不寻常的场景,其中:
- 一个外部工具同时调用我的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