gpt4 book ai didi

go - 我可以在Go中使用特定值锁定吗?

转载 作者:行者123 更新时间:2023-12-01 21:17:07 25 4
gpt4 key购买 nike

In answering another question我使用 sync.Map 编写了一些结构来缓存API请求。

type PostManager struct {
sync.Map
}

func (pc PostManager) Fetch(id int) Post {
post, ok := pc.Load(id)
if ok {
fmt.Printf("Using cached post %v\n", id)
return post.(Post)
}
fmt.Printf("Fetching post %v\n", id)
post = pc.fetchPost(id)
pc.Store(id, post)

return post.(Post)
}

不幸的是,如果两个goroutine都同时获取同一未缓存的Post,则它们都会发出请求。
var postManager PostManager

wg.Add(3)

var firstPost Post
var secondPost Post
var secondPostAgain Post

go func() {
// Fetches and caches 1
firstPost = postManager.Fetch(1)
defer wg.Done()
}()

go func() {
// Fetches and caches 2
secondPost = postManager.Fetch(2)
defer wg.Done()
}()

go func() {
// Also fetches and caches 2
secondPostAgain = postManager.Fetch(2)
defer wg.Done()
}()

wg.Wait()

我需要确保当同时提取相同的ID时,只允许一个人实际发出请求。另一个必须等​​待,并将使用缓存的Post。但是也不能锁定不同ID的获取。

在上面的示例中,我希望只有一个调用 pc.fetchPost(1)pc.fetchPost(2),并且它们应该同时进行。

Link to the full code

最佳答案

golang.org/x/sync/singleflight package正是为此目的而编写的。

请注意,所有缓存访问都应该在传递给Do的回调函数内进行。在链接到注释的代码中,您可以在外部进行查找;这有点违背了目的。

另外,您必须使用指向singleflight.Group的指针。这就是您的数据竞赛的源泉,而 vert 指出了这一点:

./foo.go:41:10: fetchPost passes lock by value: command-line-arguments.PostManager contains golang.org/x/sync/singleflight.Group contains sync.Mutex



这是我的写法(操场上的完整示例: https://play.golang.org/p/2hE721uA88S):
import (
"strconv"
"sync"

"golang.org/x/sync/singleflight"
)

type PostManager struct {
sf *singleflight.Group
cache *sync.Map
}

func (pc *PostManager) Fetch(id int) Post {
x, _, _ := pc.sf.Do(strconv.Itoa(id), func() (interface{}, error) {
post, ok := pc.cache.Load(id)
if !ok {
post = pc.fetchPost(id)
pc.cache.Store(id, post)
}

return post, nil
})

return x.(Post)
}

关于go - 我可以在Go中使用特定值锁定吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60198582/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com