Dictionary 如何解决Golang map的并发访问?

Dictionary 如何解决Golang map的并发访问?,dictionary,go,concurrency,mutex,Dictionary,Go,Concurrency,Mutex,现在我有了一个只包含一个写/删除goroutine和多个读goroutine的映射,有一些解决方案,比如RWMutex、sync.map、sync.atomic、sync.Value,我的最佳选择是什么 RWMutex的读锁有点冗余 sync.map和concurrent map关注于许多write goroutines您的问题有点模糊,所以我将对其进行细分 我应该对地图使用何种形式的并发访问 选择取决于您从映射中需要的性能。我会选择一种基于简单互斥(或RWMutex)的方法 诚然,您可以从一个

现在我有了一个只包含一个写/删除goroutine和多个读goroutine的映射,有一些解决方案,比如RWMutex、sync.map、sync.atomic、sync.Value,我的最佳选择是什么

RWMutex的读锁有点冗余


sync.map和concurrent map关注于许多write goroutines

您的问题有点模糊,所以我将对其进行细分

我应该对地图使用何种形式的并发访问

选择取决于您从映射中需要的性能。我会选择一种基于简单互斥(或RWMutex)的方法

诚然,您可以从一个新的应用程序中获得更好的性能
sync.Mutex
锁定映射存储桶中的所有存储桶,而在并发映射中,每个存储桶都有自己的
sync.Mutex

同样,这完全取决于你的计划规模和你所需要的性能

如何使用互斥来进行并发访问

要确保正确使用映射,可以将其包装在
结构中

type Store struct {
    Data              map[T]T
}
这是一个更面向对象的解决方案,但它允许我们确保任何读/写操作都是并发执行的。除此之外,我们还可以轻松地存储其他可能对调试或安全性有用的信息,例如author

现在,我们将使用一组方法来实现这一点,如下所示:

mux sync.Mutex

// New initialises a Store type with an empty map
func New(t, h uint) *Store {
    return &Store{
        Data:     map[T]T{},
    }
}

// Insert adds a new key i to the store and places the value of x at this location
// If there is an error, this is returned - if not, this is nil
func (s *Store) Insert(i, x T) error {
    mux.Lock()
    defer mux.Unlock()
    _, ok := s.Data[i]
    if ok {
        return fmt.Errorf("index %s already exists; use update", i)
    }
    s.Data[i] = x
    return nil
}

// Update changes the value found at key i to x
// If there is an error, this is returned - if not, this is nil
func (s *Store) Update(i, x T) error {
    mux.Lock()
    defer mux.Unlock()
    _, ok := s.Data[i]
    if !ok {
        return fmt.Errorf("value at index %s does not exist; use insert", i)
    }
    s.Data[i] = x
    return nil
}

// Fetch returns the value found at index i in the store
// If there is an error, this is returned - if not, this is nil
func (s *Store) Fetch(i T) (T, error) {
    mux.Lock()
    defer mux.Unlock()
    v, ok := s.Data[i]
    if !ok {
        return "", fmt.Errorf("no value for key %s exists", i)
    }
    return v, nil
}

// Delete removes the index i from store
// If there is an error, this is returned - if not, this is nil
func (s *Store) Delete(i T) (T, error) {
    mux.Lock()
    defer mux.Unlock()
    v, ok := s.Data[i]
    if !ok {
        return "", fmt.Errorf("index %s already empty", i)
    }
    delete(s.Data, i)
    return v, nil
}
在我的解决方案中,我使用了一个简单的
sync.Mutex
——但您可以简单地更改此代码以适应RWMutex


我建议你看看。

正确的选择取决于许多因素,在所有情况下,没有选择是最佳的。使用RWMutex。因此,在我的情况下(只有一个写/删除goroutine和数千个读goroutine),RWMutex是一个不错的选择?不管您有多少读/写goroutine,而是有多少实际读/写goroutine。成千上万的读goroutine每天读一次,每300ns写一次goroutine可能不是你所拥有的,但它说明了这个问题。您首先必须弄清楚您的度量标准。RWMutex是一个很好的解决方案,因为它很简单。如果您有1e8读/秒和1e4写/秒,那么保护单个映射的简单RWMutex在代码简单性方面可能仍然是最佳的,但在吞吐量和锁争用方面可能不是最佳的。你首先要知道什么对你很重要。实际上,读操作的数量是写/删除操作数量的数万倍。第二个goroutine每天的值与用户数量成正比,用户数量可能从数百增长到数百万,吞吐量非常重要,正如上面的评论所述,现在我有一个write/delete goroutine每天可能有数百或数百万次操作,还有许多读goroutine,它们的ops数量可能是写/删除ops的数万倍。RWmutex在吞吐量方面是否优于sync.map@白栋天 使用RWMutex尝试我的上述解决方案,并根据您期望的操作数对其进行基准测试。对sync.Map的性能有不同的看法,因此可能值得先做一些研究: