首先我们来看一个例子:

    运行程序,可以得到类似输出结果:

    1. 2018/03/23 14:53:28 name is 小明
    2. 2018/03/23 14:53:29 name is 小红
    3. 2018/03/23 14:53:29 name is 小红

    可以看到在两个 goroutine 中我们都可以访问 name 这个变量,当修改它后,在不同的 goroutine 中都可以同时获取到最新的值。

    下面再来看一个例子:

    多次运行代码,可以得到类似输出:

    1. The numbers is [0 1 5 4 7]
    2. The numbers is [0 5 7]

    可以看到当我们并发对同一个切片进行写操作的时候,会出现数据不一致的问题,这就是一个典型的共享变量的问题。

    修改过后,我们再次运行代码,可以看到最后的 numbers 都会包含 0~9 这个10个数字。

    sync.Mutex 是互斥锁,只有一个信号标量;在 Go 中还有一种读写锁 sync.RWMutex,对于我们的共享对象,如果可以分离出读和写两个互斥信号的情况,可以考虑使用它来提高读的并发性能。

    例如代码:

    1. package main
    2. import (
    3. "fmt"
    4. "sync"
    5. "sync/atomic"
    6. "time"
    7. )
    8. func main() {
    9. var (
    10. mux sync.Mutex
    11. "a": 65,
    12. }
    13. muxTotal uint64
    14. rw sync.RWMutex
    15. state2 = map[string]int{
    16. "a": 65,
    17. }
    18. rwTotal uint64
    19. )
    20. for i := 0; i < 10; i++ {
    21. go func() {
    22. for {
    23. mux.Lock()
    24. _ = state1["a"]
    25. mux.Unlock()
    26. atomic.AddUint64(&muxTotal, 1)
    27. }
    28. for i := 0; i < 10; i++ {
    29. go func() {
    30. for {
    31. rw.RLock()
    32. _ = state2["a"]
    33. rw.RUnlock()
    34. atomic.AddUint64(&rwTotal, 1)
    35. }
    36. }()
    37. }
    38. time.Sleep(time.Second)
    39. fmt.Println("sync.Mutex readOps is", muxTotal)
    40. fmt.Println("sync.RWMutex readOps is", rwTotal)
    41. }

    可以看到使用 sync.RWMutex 的读的并发能力大概是 sync.Mutex 的十倍,从而大大提高了其并发能力。

    • 我们可以通过共享内存的方式实现多个 goroutine 中的通信。
    • 对于可以分离为读写操作的共享数据可以考虑使用 来提高其读的并发能力。