【go 源码】sync.Once 详解

xmge · · 807 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

# sync.Once 源码阅读 ## 1.Demo ```go package main import ( "fmt" "sync" "time" ) func main() { var once sync.Once for i:=0;i<=10;i++{ go once.Do(func() { fmt.Println("hello world") }) } time.Sleep(time.Second * 2) } ``` ## 2.介绍 sync.Once是sync包中的一个对象,它只有一个方法Do,这个方法很特殊,在程序运行过程中,无论被多少次调用,只会执行一次,就与结构体的名称一样,once(一次)。那它是如何做的呢? ## 3.使用场景 当程序运行过程中,在会被多次调用的地方却只想执行一次某代码块。就可以全局声明一个once,然后用once.Do()来之行此代码块。 ## 4.源码 ```go // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package sync import ( "sync/atomic" ) // Once is an object that will perform exactly one action. type Once struct { m Mutex done uint32 } // Do calls the function f if and only if Do is being called for the // first time for this instance of Once. In other words, given // var once Once // if once.Do(f) is called multiple times, only the first call will invoke f, // even if f has a different value in each invocation. A new instance of // Once is required for each function to execute. // // Do is intended for initialization that must be run exactly once. Since f // is niladic, it may be necessary to use a function literal to capture the // arguments to a function to be invoked by Do: // config.once.Do(func() { config.init(filename) }) // // Because no call to Do returns until the one call to f returns, if f causes // Do to be called, it will deadlock. // // If f panics, Do considers it to have returned; future calls of Do return // without calling f. // func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 1 { return } // Slow-path. o.m.Lock() defer o.m.Unlock() if o.done == 0 { defer atomic.StoreUint32(&o.done, 1) f() } } ``` ## 5.源码解析 可以看到once结构体中,有两个字段,m是了保证并发安全性的,done是标志是否已经执行过此方法,如果done是1则表示执行过,0表示未执行。 Do方法中,首先通过atomic.LoadUint32(&o.done),来取得done的值,看是否为1,如果为1就表示已经执行过了,直接返回,未执行则继续执行。 代码很简单,就不啰嗦了,值得注意的是 `defer atomic.StoreUint32(&o.done, 1)`很精髓,为了防止f()方法中panic,无法为done赋值,作者特地使用defer。值得学习。 ---- 项目地址:github.com/xmge/gosc,更多go源码阅读文章将在公众号发布: ![img](https://gosc.oss-cn-beijing.aliyuncs.com/gosc.jpg)

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

807 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传