我的学习日志 我的学习日志
首页
  • Go

    • Go基础知识
  • Python

    • Python进阶
  • 操作系统
  • 计算机网络
  • MySQL
  • 学习笔记
  • 常用到的算法
其他技术
  • 友情链接
  • 收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

xuqil

一介帆夫
首页
  • Go

    • Go基础知识
  • Python

    • Python进阶
  • 操作系统
  • 计算机网络
  • MySQL
  • 学习笔记
  • 常用到的算法
其他技术
  • 友情链接
  • 收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 环境部署

  • 测试

  • 反射

  • 数据库操作

  • 并发编程

    • 解密 go Context 包
    • 深入了解Mutex和RWMutex
    • atomic 的使用
    • sync.Once 的使用
      • Once 的使用
      • Once 的实现
    • 深入理解 sync.Pool
    • 深入理解 sync.WaitGroup
    • 深入理解 channel
  • 内存管理

  • Go 技巧

  • 《go基础知识》
  • 并发编程
Xu Qil
2023-02-27
0
目录

sync.Once 的使用

# sync 包——Once

# Once 的使用

sync.One一般用来确保某个动作至多执行一次。普遍用于初始化资源、单例模式。

单例模式的实现:

type MyBusiness interface {
	DoSomething()
}

// singleton 单例模式(一般与接口一起使用)
type singleton struct {
}

func (s singleton) DoSomething() {
	//TODO implement me
	panic("implement me")
}

var instance *singleton
var singletonOnce sync.Once

// GetSingleton 属于懒加载
func GetSingleton() MyBusiness {
	singletonOnce.Do(func() {
		instance = &singleton{}
	})
	return instance
}

// init 属于饥饿模式
func init() {
	// 用包初始化函数取代 One
	instance = &singleton{}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# Once 的实现

// Once is an object that will perform exactly one action.
//
// A Once must not be copied after first use.
//
// In the terminology of the Go memory model,
// the return from f “synchronizes before”
// the return from any call of once.Do(f).
type Once struct {
   // done indicates whether the action has been performed.
   // It is first in the struct because it is used in the hot path.
   // The hot path is inlined at every call site.
   // Placing done first allows more compact instructions on some architectures (amd64/386),
   // and fewer instructions (to calculate offset) on other architectures.
   done uint32
   m    Mutex
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Once 使用的也是 double-check 的变种 ,没有直接利用读写锁,而是利用原子操作来扮演读锁的角色。

func (o *Once) Do(f func()) {
   // Note: Here is an incorrect implementation of Do:
   //
   // if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
   //    f()
   // }
   //
   // Do guarantees that when it returns, f has finished.
   // This implementation would not implement that guarantee:
   // given two simultaneous calls, the winner of the cas would
   // call f, and the second would return immediately, without
   // waiting for the first's call to f to complete.
   // This is why the slow path falls back to a mutex, and why
   // the atomic.StoreUint32 must be delayed until after f returns.

   if atomic.LoadUint32(&o.done) == 0 {
      // Outlined slow-path to allow inlining of the fast-path.
      o.doSlow(f)
   }
}

func (o *Once) doSlow(f func()) {
   o.m.Lock()
   defer o.m.Unlock()
   if o.done == 0 {
      defer atomic.StoreUint32(&o.done, 1)
      f()
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

评论

上次更新: 2023/03/01, 07:47:26
atomic 的使用
深入理解 sync.Pool

← atomic 的使用 深入理解 sync.Pool→

最近更新
01
Golang 逃逸分析
03-22
02
深入理解 channel
03-04
03
深入理解 sync.WaitGroup
03-01
更多文章>
Theme by Vdoing | Copyright © 2018-2023 FeelingLife | 粤ICP备2022093535号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式