六、《go 并发编程》读写锁

173 阅读2分钟
先来理解下

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 可以同时读

写,进行的时候,其它的读和写都会被阻塞