美文网首页
【Go - sync.once】

【Go - sync.once】

作者: wn777 | 来源:发表于2024-07-24 01:19 被阅读0次

sync.Once 是 Go 语言标准库中的一个结构体,它的作用是确保某个操作在全局范围内只被执行一次。这对于实现单例模式或需要一次性初始化资源的场景非常有用。

典型用法

sync.Once 提供了一个方法 Do(f func()),该方法接收一个没有参数和返回值的函数 f 作为参数。无论 Do 方法被调用多少次,函数 f 只会被执行一次。

var once sync.Once

func setup() {
    // 初始化操作,只会执行一次
}

func main() {
    // 即使在多线程环境下,setup函数也只会被执行一次
    once.Do(setup)
    once.Do(setup) // 这次调用不会执行setup
}

多CPU下跑 - 示例

依然只执行一次

package main

import (
    "fmt"
    "runtime"
    "sync"
)

var once sync.Once
var wg sync.WaitGroup

func setup() {
    // 初始化操作,只会执行一次
    fmt.Println("init")
}

func main() {
    // 设置GOMAXPROCS为机器上的CPU核心数
    // 让协程同时跑在多个CPU上
    numCPU := runtime.NumCPU()
    runtime.GOMAXPROCS(numCPU)
    fmt.Printf("Running with %d CPUs\n", numCPU)

    // 即使在多核CPU下的多协程环境下,setup函数也只会被执行一次
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            once.Do(setup)
            fmt.Printf("Running in goroutine %d\n", i)
        }(i)
    }

    wg.Wait()
    fmt.Println("Done")
}

原理

sync.Once 的实现原理基于 Go 语言的内存模型和同步原语,主要通过两个字段控制:一个是 done,用于标记函数 f 是否已经执行过;另一个是互斥锁 m,用于在多个 goroutine 同时调用 Do 方法时保证只有一个能执行函数 f

  1. Do 方法第一次被调用时,done 字段为 0,表示函数 f 还没有执行。
  2. Do 方法会先检查 done 字段,如果 f 已经执行(done 不为 0),则直接返回。
  3. 如果 f 还没有执行,Do 方法会加锁并再次检查 done 字段,以防在等待锁的过程中 f 被执行。
  4. 如果 f 确实还没有执行,Do 方法会执行函数 f,然后将 done 设置为 1 并释放锁。

这种设计确保了即使在高并发的情况下,函数 f 也只会被执行一次,同时避免了不必要的加锁操作,提高了效率。

相关文章

  • Go语言——sync.Once分析

    Go语言——sync.Once分析 sync.Once表示只执行一次函数。要做到这点,就需要两点: 计数器,统计函...

  • sync.Once

    sync.Once 的使用场景 sync.Once 是 Go 标准库提供的使函数只执行一次的实现,常应用于单例模式...

  • go 中的 sync.Once

    sync.Once 是 Go 标准库提供的使函数只执行一次的实现,常应用于单例模式,sync.Once 仅提供了一...

  • golang 系列:sync.Once 讲解

    sync.Once 介绍 之前提到过 Go 的并发辅助对象:WaitGroup[https://mp.weixin...

  • Go - sync.Once

    设计目的 Once 常常用来初始化单例资源,或者并发访问只需初始化一次的共享资源,或者在测试的时候初始化一次测试资...

  • 深度剖析Golang sync.Once源码

    目录 什么是sync.Once 如何使用sync.Once 源码分析 什么是sync.Once Once 可以用来...

  • go单例模式之懒汉模式

    可以通过sync包中的sync.Once实现单例模式。 如下是once.go中的Do()方法的源码: 下面是用sy...

  • sync.Once

    利用 sync.once 实现单例 sync.Once 实现 为什么要用defer 来加计数?不直接在后面执行计数...

  • golang sync.Once源代码阅读--让你的初始化只执行

    sync.Once的用处 sync.Once 主要用途执行只需要执行一次的初始化函数,比如验证器的初始,http....

  • GO 语言sync.WaitGroup和sync.Once

    sync.WaitGroup sync.WaitGroup类型(以下简称WaitGroup类型)是开箱即用的,也是...

网友评论

      本文标题:【Go - sync.once】

      本文链接:https://www.haomeiwen.com/subject/zjpuhjtx.html