sync.Once解决了什么问题

本文探讨了解决变量懒加载情况下并发请求导致的数据竞争问题,通过比较使用互斥锁与sync.Once的优劣,并举例展示了如何利用sync.Once简化代码,确保并发安全。同时,提到了race竞争检查的重要性及其实例应用。

解决的问题:

解决变量懒加载情况下并发请求数据竞争的问题。

懒加载的Demo:

var icons map[string]int

func loadIcons() {
	icons = map[string] int{
		"a": 1,
		"b": 2,
		"c": 3,
		"d": 4,
	}
}
// 并发不安全
func Icon(name string) int {
	if icons == nil {
		loadIcons() // 懒加载的行为  只有在将要使用的时候再进行初始化
	}
	return icons[name]
}

使用互斥锁的机制实现并发的懒加载:

import "sync"

var mu sync.RWMutex

var icons map[string]int

func loadIcons() {
	icons = map[string] int{
		"a": 1,
		"b": 2,
		"c": 3,
		"d": 4,
	}
}
// 并发安全的
func Icon(name string) int {
	// 读锁 保证了读的并发安全性
	mu.RLock()
	if icons != nil {
		icon := icons[name]
		mu.RUnlock()
		return icon
	}
	mu.RUnlock()

	// 互斥锁, 保证了初始化变量的并发安全性。
	mu.Lock()
	if icons == nil {
		loadIcons()
	}
	icon := icons[name]
	mu.Unlock()
	return icon
}

显然互斥锁的部分,再初次执行后,后面永远不可能执行到。显得代码非常的麻烦。
sync.Once 可以优化这种情况。

var loadIconsOnce sync.Once
var icons map[string] int

func Icon(name string) int {
	loadIconsOnce.Do(loadIcons)
	return icons[name]
}

sync.Once 一次性的初始化需要一个互斥量mutex和一个boolean变量来记录初始化是不是已经完成了。mutex同步会保证loadIcons对内存产生的效果能够对所有 sync.Once初始化goroutine可见。用这种方式来使用sync.Once的话,我们能够避免在变量被构建完成之前和其它goroutine共享该变量

race 竞争检查:(用来检查我们的代码是否存在竞争的情况)
需要注意命令的放置位置:

// 需要注意命令放置的位置
go run -race bank4.go
go build -race bank3.go 

竞争检查示例:

F:\github\demo\shareParams\bank4>go run -race bank4.go
begin
= 200
==================
WARNING: DATA RACE
Write at 0x000000639610 by goroutine 8:
  main.deposit()
      F:/github/demo/shareParams/bank4/bank4.go:38 +0x9c
  main.Withdraw()
      F:/github/demo/shareParams/bank4/bank4.go:30 +0x75
  main.main.func2()
      F:/github/demo/shareParams/bank4/bank4.go:52 +0x91

Previous read at 0x000000639610 by goroutine 7:
  main.Balance()
      F:/github/demo/shareParams/bank4/bank4.go:24 +0x7b
  main.main.func1()
      F:/github/demo/shareParams/bank4/bank4.go:47 +0x89

Goroutine 8 (running) created at:
  main.main()
      F:/github/demo/shareParams/bank4/bank4.go:50 +0x176

Goroutine 7 (finished) created at:
  main.main()
      F:/github/demo/shareParams/bank4/bank4.go:44 +0x10e
==================
取款成功
200
Found 1 data race(s)
exit status 66

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值