锁
首先我们来看一个例子:
运行程序,可以得到类似输出结果:
2018/03/23 14:53:28 name is 小明
2018/03/23 14:53:29 name is 小红
2018/03/23 14:53:29 name is 小红
可以看到在两个 goroutine 中我们都可以访问 name
这个变量,当修改它后,在不同的 goroutine 中都可以同时获取到最新的值。
下面再来看一个例子:
多次运行代码,可以得到类似输出:
The numbers is [0 1 5 4 7]
The numbers is [0 5 7]
可以看到当我们并发对同一个切片进行写操作的时候,会出现数据不一致的问题,这就是一个典型的共享变量的问题。
修改过后,我们再次运行代码,可以看到最后的 numbers 都会包含 0~9 这个10个数字。
sync.Mutex
是互斥锁,只有一个信号标量;在 Go 中还有一种读写锁 sync.RWMutex
,对于我们的共享对象,如果可以分离出读和写两个互斥信号的情况,可以考虑使用它来提高读的并发性能。
例如代码:
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
var (
mux sync.Mutex
"a": 65,
}
muxTotal uint64
rw sync.RWMutex
state2 = map[string]int{
"a": 65,
}
rwTotal uint64
)
for i := 0; i < 10; i++ {
go func() {
for {
mux.Lock()
_ = state1["a"]
mux.Unlock()
atomic.AddUint64(&muxTotal, 1)
}
for i := 0; i < 10; i++ {
go func() {
for {
rw.RLock()
_ = state2["a"]
rw.RUnlock()
atomic.AddUint64(&rwTotal, 1)
}
}()
}
time.Sleep(time.Second)
fmt.Println("sync.Mutex readOps is", muxTotal)
fmt.Println("sync.RWMutex readOps is", rwTotal)
}
可以看到使用 sync.RWMutex
的读的并发能力大概是 sync.Mutex
的十倍,从而大大提高了其并发能力。
- 我们可以通过共享内存的方式实现多个 goroutine 中的通信。
- 对于可以分离为读写操作的共享数据可以考虑使用 来提高其读的并发能力。