竞争资源是多个 goroutine 在没有相互同步的情况下,访问某个共享的资源,也叫竞态资源。
比如同时对该资源进行读写时,就会处于相互竞争的状态,这就是并发中的资源竞争。对竞争资源处理不当时会有性能损耗,也可能会引起其它问题。
可以用 Race Detector
(竞态分析)来找到竞态资源,工具的使用方法就是在 go test/build
后加上 -race
标志
1
2
$ go test -v -race
$ go build -race
静态资源有多种同步机制
- 使用channel
- 使用Mutex
- 使用atomic
- 使用unsafe.Pointer
性能上 atomic
和 unsafe.Pointer
差不多,Mutex
较慢,channel
最慢。
下面是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 例子
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 转摘请注明来源