我想用Go实现一个singleton。与普通的singleton不同的是,实例是在map结构中用不同的key实现的singleton。类似这样的代码。我不知道这段演示代码是否存在数据竞赛。
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
Map就像Go的map[interface{}]interface{}一样,但对于多个goroutine的并发使用是安全的,不需要额外的锁定或协调。加载、存储和删除都是以摊开的恒定时间运行的。
Map类型针对两种常见的用例进行了优化。(1)当一个给定的键的条目只被写入一次,但却被多次读取,比如在只会增长的缓存中;或者(2)当多个goroutine读取、写入和覆盖不相干键集的条目时。
在这两种情况下,与Go map与单独的Mutex或RWMutex配对相比,使用Map可以显著减少锁的争用。
注意事项: 在第三段中,它提到为什么使用 sync.Map
是有益的,而不是简单地将Go Map与之搭配使用。sync.RWMutex
.
所以这完全符合你的情况吧?
回答得有点晚,总之这个应该能帮到你。https:/github.comashwinshirvaapitreemasterdpsingleton.
这显示了两种实现singleton的方法。
sync.Mutex
sync.Once