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 泛型性能初识

编程时,我们通常需要编写“泛型”函数,其中确切的数据类型并不重要。例如,您可能想编写一个简单的函数来对数字进行求和。Go 直到最近才有这个概念,但最近才添加了它(从1.18版开始)。...

Golang Range 的性能提升Tip

Go 语言里使用 range 可以方便遍历数组(array)、切片(slice)、字典(map)和信道(chan)。这里主要关注他们的性能。...

Golang 时区时差处理方式

个人习惯用 0 时区时间戳记录时间,可以方便转到不同时区,下面介绍 Golang 时区时差处理...

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

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