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

标签 go mutex

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/

相关文章:

go - 在 Go 中是否有实现静态变量的模式?

C++ - 没有像 mutex_Lock 这样的协调机制的线程

c++ - 这段代码是线程安全的吗?

去 : How function with different return type than declaration is working fine in golang

C 对如何初始化和实现 pthread 互斥体和条件变量感到困惑

language-agnostic - 自旋锁是如何在底层实现的?

c++ - C++ mutex 和 RTOS xMutex 的区别

c - 如何在 Linux 中编写文本模式的图形用户界面?

http - 由于来自服务器的 mime 不正确,无法使用 Go 打开 Zip

go - 如何在 lambda 处理程序回复后等待 goroutine 完成