go 单例模式
golang中单例模式体现在很多地方, 比如init函数,当包被导入的时候只会被执行一次。实现单例模式有很多种方式,这里给出几种简单的实现:
互斥锁
对全局共享变量加锁,如果该变量不是nil,那么证明已经被创建了实例,直接返回它的值就好。
type singleton struct {}
var (
ins *singleton
mu sync.Mutex
)
func Instance() *singleton {
mu.Lock()
defer mu.Unlock()
if ins == nil {
ins = &singleton{}
}
return ins
}
互斥锁 + 原子操作
看到有别的文章说,加互斥锁是比较耗时的,我们可以使用一个变量来标识是否已经被实例化,维护该变量只需要go中原生支持的原子操作:atomic。
var (
ins *singleton
mu sync.Mutex
created uint32
)
func Instance2() *singleton {
if atomic.LoadUint32(&created) == 1 {
return ins
}
mu.Lock()
defer mu.Unlock()
if ins == nil {
ins = &singleton{}
atomic.StoreUint32(&created, 1)
}
return ins
}
使用go中的benchmark跑了一下,好像这种实现和上一种性能上没什么区别......可能是例子过于简单了吧,后续找到原因再更(希望不要忘hhhh~)
Once
通过atomic+mutex的方式实现单例模式,其实就是go中Once的实现方式。
var (
ins *singleton
once sync.Once
)
func Instance3() *singleton {
once.Do(func() {
ins = &singleton{}
})
return ins
}