数据安全与锁
4.1、互斥锁
互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine
可以访问共享资源。Go语言中使用sync
包的Mutex
类型来实现互斥锁。
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var lock sync.Mutex
var x = 0
func add() {
//lock.Lock()
x++
//lock.Unlock()
wg.Done()
}
func main() {
wg.Add(1000)
for i:=0;i<1000 ;i++ {
go add()
}
wg.Wait()
fmt.Println(x)
}
使用互斥锁能够保证同一时间有且只有一个goroutine
进入临界区,其他的goroutine
则在等待锁;当互斥锁释放后,等待的goroutine
才可以获取锁进入临界区,多个goroutine
同时等待一个锁时,唤醒的策略是随机的。
4.2、读写锁
在读多写少的环境中,可以优先使用读写互斥锁(sync.RWMutex),它比互斥锁更加高效。sync 包中的 RWMutex 提供了读写互斥锁的封装。
package main
import (
"fmt"
"sync"
"time"
)
// 效率对比
// 声明读写锁
var rwlock sync.RWMutex
var mutex sync.Mutex
var wg sync.WaitGroup
// 全局变量
var x int
// 写数据
func write() {
//mutex.Lock()
rwlock.Lock()
x += 1
fmt.Println("x",x)
time.Sleep(10 * time.Millisecond)
//mutex.Unlock()
rwlock.Unlock()
wg.Done()
}
func read(i int) {
//mutex.Lock()
rwlock.RLock()
time.Sleep(time.Millisecond)
fmt.Println(x)
//mutex.Unlock()
rwlock.RUnlock()
wg.Done()
}
// 互斥锁执行时间:18533117400
// 读写锁执行时间:1312065700
func main() {
start := time.Now()
wg.Add(1)
go write()
for i := 0; i < 1000; i++ {
wg.Add(1)
go read(i)
}
wg.Wait()
fmt.Println("运行时间:", time.Now().Sub(start))
}
4.3、map锁
Go语言中内置的map不是并发安全的.
并发读是安全的
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
m := make(map[int]int)
// 添一些假数据
for i := 0; i < 5; i++ {
m[i] = i*i
}
// 遍历打印
for i := 0; i < 5; i++ {
wg.Add(1)
go func(x int) {
fmt.Println(m[x], "\t")
wg.Done()
}(i)
}
wg.Wait()
fmt.Println(m)
}
并发写则不安全
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
//m := make(map[int]int)
var m = sync.Map{}
// 并发写
for i := 0; i < 100; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
m.Store(i,i*i)
}(i)
}
wg.Wait()
fmt.Println(m.Load(1))
fmt.Println(m.Load(2))
}
4.4、原子性操作
-
加锁操作比较耗时,整数可以使用原子操作保证线程安全
-
原子操作在用户态就可以完成,因此性能比互斥锁高
提示
AddXxx():加减操作
提示
CompareAndSwapXxx():比较并交换
提示
LoadXxx():读取操作
提示
StoreXxx():写入操作
提示
SwapXxx():交换操作
原子操作与互斥锁性能对比:
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
// 效率对比
// 原子操作需要接收int32或int64
var x int32
var wg sync.WaitGroup
var mutex sync.Mutex
// 互斥锁操作
func add1() {
for i := 0; i < 500; i++ {
mutex.Lock()
x += 1
mutex.Unlock()
}
wg.Done()
}
// 原子操作
func add2() {
for i := 0; i < 500; i++ {
atomic.AddInt32(&x, 1)
}
wg.Done()
}
func main() {
start := time.Now()
for i := 0; i < 10000; i++ {
wg.Add(1)
go add1()
//go add2()
}
wg.Wait()
fmt.Println("x:", x)
fmt.Println("执行时间:", time.Now().Sub(start))
}