我遇到了一种不同寻常的情况:

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

这是可行的,但它会同时多次获取相同的配置文件,而实际上它只能获取一次.为了试验这一点,我在这里有一个最小版本https://go.dev/play/p/Nx-kidmprQx,它返回随机整数,而不是进行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

我正在努力想出解决这一问题的办法.多个大猩猩应该等待一个结果的事实令人困惑.怎么可能做到呢?

推荐答案

您可以使用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 start\n", 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

Go相关问答推荐

Golang regexpp:获取带有右括号的单词

Gorm foreign 密钥

Go Regexp:匹配完整的单词或子字符串,或者根本不匹配

使用GO从RDPMC获得价值

MaybeReadByte对通道的使用如何在Go中提供随机行为?

Go SQLCMD比Windows本机版本慢吗?

由docker中的nginx提供的样式和图像在页面上不起作用

如何将字节文件高效地读入int64切片?

在 Cloud Run 中找不到默认凭据

如何使用 go-git 将特定分支推送到远程

使用 os/exec 和在命令行执行之间的结果莫名其妙地不同

如何确定作为函数参数传递的指针是否正在被修改或副本是否正在被修改?

Golang - 将 [8] 布尔转换为字节

为什么时间很短.睡眠时间比基准测试中要求的(约 300 ns)长?

try 运行 docker-compose up -d 时出现错误

Golang 工作池实现意外工作

Golang prometheus 显示自定义指标

自定义指标未显示在 prometheus web ui 中,grafana 中也是如此

Go:如何通过 GIN-Router 从 AWS S3 将文件作为二进制流发送到浏览器?

Go 泛型是否与 LINQ to Objects 等效?