1 简介

代码中的加锁操作因为涉及内核态的上下文切换会比较耗时、代价比较高。针对基本数据类型我们还可以使用原子操作来保证并发安全,因为原子操作是Go语言提供的方法, 它在用户态就可以完成,因此性能比加锁操作更好。

2 代码示例

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "sync/atomic"
  6. "time"
  7. )
  8. var x int64
  9. var l sync.Mutex
  10. var wg sync.WaitGroup
  11. // 普通版加函数
  12. func add() {
  13. // x = x + 1
  14. x++ // 等价于上面的操作
  15. wg.Done()
  16. }
  17. // 互斥锁版加函数
  18. func mutexAdd() {
  19. l.Lock()
  20. x++
  21. l.Unlock()
  22. wg.Done()
  23. }
  24. // 原子操作版加函数
  25. func atomicAdd() {
  26. atomic.AddInt64(&x, 1)
  27. wg.Done()
  28. }
  29. func main() {
  30. start := time.Now()
  31. for i := 0; i < 1000000; i++ {
  32. wg.Add(1)
  33. //go add() // 普通版add函数 不是并发安全的 241.894648ms
  34. //go mutexAdd() // 加锁版add函数 是并发安全的,但是加锁性能开销大 302.15573ms
  35. go atomicAdd() // 原子操作版add函数 是并发安全,性能优于加锁版 251.501716ms
  36. }
  37. wg.Wait()
  38. end := time.Now()
  39. fmt.Println(x)
  40. fmt.Println(end.Sub(start))
  41. }