Go之sync.Once

Role: sync.Once can ensure that the Do method of the instantiated object only runs once in a multi-threaded environment, and is implemented internally through a mutex lock.

For example, an operation only needs to be performed once, and when multiple goroutines operate at the same time, it is guaranteed to operate only once and not repeat operations.

sync.Once means to execute the function only once. To do this, two things are needed:

(1) Counter, count the number of function executions;

(2) Thread safety, to ensure that in the case of multiple G, the function is still executed only once, such as a lock.

Example 1:

A thread-safe singleton pattern

package singleton

import (
    "fmt"
    "sync"
)

type object struct {
    name string
}

var once sync.Once
var obj *object //单例指针

//公开方法 外包调用
func Instance() *object {
    once.Do(getObj)
    return obj
}

func getObj() {
    if obj == nil {
        obj = new(object)
        //可以做其他初始化事件
    }
}

//单例测试
func (obj *object) Test() {
    fmt.Println(obj.name)
}

Example 2:

Although the once.Do () method is called every time in the for loop , the onceBody () function is only executed once. 

package main

import (
        "fmt"
        "sync"
        "time"
)

var once sync.Once
var onceBody = func() {
    fmt.Println("Only once")
}

func main() {
        for i := 0; i < 10; i++ {
                go func(i int) {
                        once.Do(onceBody)
                        fmt.Println("i=",i)
                }()
        }
        time.Sleep(time.Second) //睡眠1s用于执行go程,注意睡眠时间不能太短
}

The Do method is quite simple, but there are also places to learn. For example, some flags can be represented by atomic operations to avoid locking and improve performance.

The implementation process of the Do method is as follows:

(1) First, the number of atomic load function executions, if it has been executed, return;

(2)lock;

(3) Executive function;

(4) The number of executions of the atomic store function 1;

(5)unlock。

Definition of sync.Once:

// Once is an object that will perform exactly one action.
type Once struct {
    m    Mutex
    done uint32
}

//使用了双层检查机制 
func (o *Once) Do(f func()) {
    if atomic.LoadUint32(&o.done) == 1 {
        return
    }
    // Slow-path.
    o.m.Lock()
    defer o.m.Unlock()
    //这里需要再次重新判断下,因为 atomic.LoadUint32取出状态值到  o.m.Lock() 之间是有可能存在其它gotoutine改变status的状态值的
    if o.done == 0 {
        f()
        atomic.StoreUint32(&o.done, 1)
    }
}

 

 

Published 127 original articles · Likes 24 · Visits 130,000+

Guess you like

Origin blog.csdn.net/Linzhongyilisha/article/details/105472298
Recommended