sync.Once的源码十分简单,而且注释十分清楚,直接来看一下。
源码
定义了一个结构体Once
type Once struct { |
对外提供了一个方法Do,Once.Do可以理解成资源初始化,只会执行一次。
func (o *Once) Do(f func()) { |
如果你熟悉atomic,这里你可能会有个疑问,Do方法里面为何不直接使用cas原子操作呢,那多简洁?
if atomic.CompareAndSwapUint32(&o.done, 0, 1) { |
其实源码注释里已经有了说明,这样的实现并不合理。
当你有2个并发请求调用Do,这样的实现确实能保证只会调用一次f。但是,假如f的执行需要一段时间,比如初始化数据库连接池,当f执行尚未完成,并发中另一个请求因为没有执行原子操作直接返回了,使用f中初始化的连接池就必然会失败,那么这样的实现显然是不可取的。
所以必须确保f执行完成之后,才能将done置为1。
使用
var one sync.Once |
可以看到只执行了一次,也就是fun1。
其实once很适合应用到单例模式,比如连接数据库,
package db |
好了,Once是很常用的,也很适合单例模式使用,源码简单明了,以后在项目中多多使用吧!