Dictionary 如何解决Golang map的并发访问?
现在我有了一个只包含一个写/删除goroutine和多个读goroutine的映射,有一些解决方案,比如RWMutex、sync.map、sync.atomic、sync.Value,我的最佳选择是什么 RWMutex的读锁有点冗余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)的方法 诚然,您可以从一个
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的性能有不同的看法,因此可能值得先做一些研究: