如何实现单例



我想用Go实现一个单例。普通单例之间的区别在于实例是单例,在映射结构中具有不同的键。类似于此代码。我不确定演示代码是否存在任何数据竞争。

var instanceLock sync.Mutex
var instances map[string]string
func getDemoInstance(key string) string {
if value, ok := instances[key]; ok {
return value
}
instanceLock.Lock()
defer instanceLock.Unlock()
if value, ok := instances[key]; ok {
return value
} else {
instances[key] = key + key
return key + key
}
}

是的,存在数据竞赛,您可以通过使用go run -race main.go运行它来确认。如果一个 goroutine 锁定并修改了映射,则另一个 goroutine 可能在锁定之前读取它。

您可以在读取时使用sync.RWMutex进行读锁定(允许多个读取器而不会相互阻止(。

例如:

var (
instancesMU sync.RWMutex
instances   = map[string]string{}
)
func getDemoInstance(key string) string {
instancesMU.RLock()
if value, ok := instances[key]; ok {
instancesMU.RUnlock()
return value
}
instancesMU.RUnlock()
instancesMU.Lock()
defer instancesMU.Unlock()
if value, ok := instances[key]; ok {
return value
}
value := key + key
instances[key] = value
return value
}

你也可以试试这个:sync。地图

Map 类似于 Go map[interface{}]interface{},但可以安全地由多个 goroutines 并发使用,无需额外的锁定或协调。加载、存储和删除在摊销的常量时间内运行。

Map 类型针对两种常见用例进行了优化:(1( 当给定键的条目只写入一次但读取多次时,例如在仅增长的缓存中,或 (2( 当多个 goroutine读取、写入和覆盖不相交键集的条目时。

在这两种情况下,与与单独的互斥或 RWMutex 配对的 Go 映射相比,使用 Map 可以显著减少锁争用。

注意:在第三段中,它提到了为什么使用sync.Map是有益的,而不是简单地使用Go Map与sync.RWMutex配对。

所以这完全适合你的情况,我猜?

回答有点晚了,无论如何这应该会有所帮助:https://github.com/ashwinshirva/api/tree/master/dp/singleton

这显示了实现单一实例的两种方法:

  1. 使用sync.Mutex
  2. 使用sync.Once

最新更新