先来理解下
RWMutex 读写锁,本质上也是
互斥锁
,在一些业务场景下,资源在产生竞争,同步只会运用到对数据进行修改的操作,也就是写的操作,而读的操作,因为对数据没有产生修改,本意上不太会发生临界安全值的问题再有一点是,互斥锁的特性,在一个 goroutine 运行的同时,不允许其它的 goroutine 运行,性能上也会大打折扣
所以
读写锁
是建立在读与写
或者写与写
的操作上的互斥锁
多个读
操作是可以同时进行的
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var mx sync.RWMutex
func main() {
wg.Add(2)
go read(1)
go read(2)
wg.Wait()
fmt.Println("全部结束。。。")
}
func read(num int) {
defer wg.Done()
fmt.Println(num, "开始读")
// 读上锁
mx.RLock()
fmt.Println(num, "正在读取")
time.Sleep(1 * time.Second)
mx.RUnlock()
// 读结束
fmt.Println(num,"读结束。。。")
}
读上锁结果
# 读操作可以同时进行
2 开始读
1 开始读
1 正在读取
2 正在读取
1 读结束。。。
2 读结束。。。
全部结束。。。
写上锁
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var mx sync.RWMutex
func main() {
wg.Add(2)
go write(1)
go write(2)
wg.Wait()
fmt.Println("全部结束。。。")
}
func write(num int) {
defer wg.Done()
fmt.Println(num, "开始写")
// 写上锁
mx.Lock()
fmt.Println(num, "正在写入")
time.Sleep(3 * time.Second)
mx.Unlock()
fmt.Println(num,"写结束。。。")
}
写上锁结果
2 开始写
2 正在写入
1 开始写
1 正在写入
2 写结束。。。
1 写结束。。。
全部结束。。。
读与写操作
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var mx sync.RWMutex
func main() {
wg.Add(3)
go write(1)
go read(2)
go write(3)
wg.Wait()
fmt.Println("全部结束。。。")
}
func write(num int) {
defer wg.Done()
fmt.Println(num, "开始写,并上锁")
// 写上锁
mx.Lock()
fmt.Println(num, "正在写入")
time.Sleep(1 * time.Second)
mx.Unlock()
fmt.Println(num,"写结束。。。")
}
func read(num int) {
defer wg.Done()
fmt.Println(num, "开始读,并上锁")
// 读上锁
mx.RLock()
fmt.Println(num, "正在读取")
time.Sleep(1 * time.Second)
mx.RUnlock()
// 读结束
fmt.Println(num, "读结束。。。")
}
读写操作结果
3 开始写,并上锁
3 正在写入
1 开始写,并上锁
2 开始读,并上锁
3 写结束。。。
2 正在读取
2 读结束。。。
1 正在写入
1 写结束。。。
全部结束。。。
结论
读,可以没有限制,多个 goroutine 可以同时读
写,进行的时候,其它的读和写都会被阻塞