并发场景中, 互斥锁 与 读写锁 是常用解决访问冲突的两种锁:

互斥锁(Mutex)

读写锁(RWMutex)

从两种锁的特性看, 读写锁能够完全替代互斥锁. 但通常提到读写锁时都会说: 读写锁用于 读多写少 的场景.

我们从 benchmark 结果看原因:

注: 不同系统/硬件结果可能不同

goos: darwin
goarch: amd64
pkg: demo
// 互斥锁 加锁
BenchmarkMutexLock-4             	300000000	        23.3 ns/op
// 读写锁 加写锁
BenchmarkRWMutexLock-4           	200000000	        38.3 ns/op
// 读写锁 加读锁
BenchmarkRWMutexRLock-4          	200000000	        31.7 ns/op
// 互斥锁 加锁+解锁
BenchmarkMutexLockUnLock-4       	200000000	        30.3 ns/op
// 读写锁 加写锁+解锁
BenchmarkRWMutexLockUnLock-4     	100000000	        54.1 ns/op
// 读写锁 加读锁+解锁
BenchmarkRWMutexRLockRUnLock-4   	200000000	        38.4 ns/op
PASS
ok  	demo	56.978s

从结果上看, 读写锁的效率会低于互斥锁! 虽然理论上读写锁可以替代互斥锁, 但不推荐!

赋上 benchmark 代码

func BenchmarkMutexLock(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var lock sync.Mutex
		lock.Lock()
	}
}

func BenchmarkRWMutexLock(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var lock sync.RWMutex
		lock.Lock()
	}
}

func BenchmarkRWMutexRLock(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var lock sync.RWMutex
		lock.RLock()
	}
}

func BenchmarkMutexLockUnLock(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var lock sync.Mutex
		lock.Lock()
		lock.Unlock()
	}
}

func BenchmarkRWMutexLockUnLock(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var lock sync.RWMutex
		lock.Lock()
		lock.Unlock()
	}
}

func BenchmarkRWMutexRLockRUnLock(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var lock sync.RWMutex
		lock.RLock()
		lock.RUnlock()
	}
}