前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go 并发实战 -- sync Once

Go 并发实战 -- sync Once

作者头像
邹志全
发布2019-07-31 10:59:55
5610
发布2019-07-31 10:59:55
举报
文章被收录于专栏:EffectiveCodingEffectiveCoding
前言

Once是一个非常实用的API,它保证了一个事情仅做一次,这个在许多场景非常有用,所以Once也是go提供的为数不多的API之一。

语法基础

Once的语法非常简单,整个API就提供了一个Do函数,Do函数接受的是一个函数对象,通过once.Do可以保证这个事情仅做一次,来看一个demo:

代码语言:javascript
复制
func main() {
    var once = sync.Once{}
    once.Do(say)
    once.Do(say)
    once.Do(say)
    once.Do(say)
}

func say() {
    fmt.Println("say once")
}

输出:

image.png

源码实现

// Once is an object that will perform exactly one action.

代码语言:javascript
复制
type Once struct {
    m    Mutex // 一把锁
    done uint32 // 是否已经做过的标记
}

func (o *Once) Do(f func()) {
// 如果已经做过了直接返回,这里使用atmoic保证并发场景下的安全性
    if atomic.LoadUint32(&o.done) == 1 {
        return
    }
// 这里有一个先判断后操作的竞态条件,所以锁了一下
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {
        // 将状态标记为已完成,这个过程还是在锁内部
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}

ps:源码中有一个细节点,如果声明了多个defer,按照定义顺序,倒序执行,这也就是为什么最终把状态置为已完成是发生在锁内部了。 关于Once的内容挺简单的,暂时先介绍这么多。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.07.10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 语法基础
  • 源码实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档