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
}
posted @ 2021-11-20 20:56  moon_orange  阅读(516)  评论(0编辑  收藏  举报