GolangNote

Golang笔记

正确处理Golang 竞争资源,提高性能

Permalink

竞争资源是多个 goroutine 在没有相互同步的情况下,访问某个共享的资源,也叫竞态资源。

比如同时对该资源进行读写时,就会处于相互竞争的状态,这就是并发中的资源竞争。对竞争资源处理不当时会有性能损耗,也可能会引起其它问题。

可以用 Race Detector (竞态分析)来找到竞态资源,工具的使用方法就是在 go test/build 后加上 -race 标志

Bash: Race Detector
1
2
$ go test -v -race
$ go build -race

静态资源有多种同步机制

  • 使用channel
  • 使用Mutex
  • 使用atomic
  • 使用unsafe.Pointer

性能上 atomicunsafe.Pointer 差不多,Mutex 较慢,channel 最慢。

下面是atomic、unsafe.Pointer、Mutex 的比较结果:

Bash: atomic、unsafe.Pointer、Mutex 的比较结果
1
2
3
4
5
6
7
8
$ go version
go version go1.10 darwin/amd64
$ go test -bench .
goos: darwin
goarch: amd64
BenchmarkPointer-8   	100000000	        12.2 ns/op
BenchmarkValue__-8   	100000000	        14.6 ns/op
BenchmarkRWMutex-8   	 5000000	       302 ns/op

go1.10 后 atomic 改变了不少,跟 unsafe.Pointer 相差很小。

原子操作atomic

共有五种操作:增减, 比较并交换, 载入, 存储,交换(T代表int32、int64、uint32、uint64、unitptr、pointer(没有增减操作))

  • func LoadT(addr *T) (val T) :读取;
  • func StoreT(addr *T, val T):写入;
  • func AddT(addr *T, delta T) (new T):增减,返回新的值;
  • func SwapT(addr *T, new T) (old T):交换,并返回旧值;
  • func CompareAndSwapT(addr *T, old, new T) (swapped bool):比较addr中保存的值是否与old相等,若相等则替换为新值,并返回true;否则,直接返回false。

atomic 例子

Go: atomic
1
2
3
4
5
6
7
8
9
10
var sum uint32 = 100

atomic.CompareAndSwapUint32(&sum, 100, sum+1) // 101
atomic.CompareAndSwapUint32(&sum, 100, sum+1) // 101,不等没有变化
atomic.AddUint32(&sum, 1) // 102

var count int32 = 0

//  如果count变量的值为0,才将100保存到变量中,保存成功返回true,反之false
ok := atomic.CompareAndSwapInt32(&count, 0, 100)

本文网址: https://golangnote.com/topic/225.html 转摘请注明来源

Related articles

Golang sync.WaitGroup 的 Wait 超时处理

sync.WaitGroup 使用 `Add(1)`、`Done()`、`Wait()`组合来实现多协程等待,如果某一协程未能合理处理错误,导致无法退出,此时需要引入超时机制。下面是一种超时处理方法。...

Write a Comment to "正确处理Golang 竞争资源,提高性能"

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.17 Processed in 0ms