Go学习笔记—原子计算器、互斥锁、Go状态协程
1、原子计算器atomic-counters
状态管理方式除了通过通道间的沟通完成,还可以使用原子计算的方法。
原子计算在sync/atomic
包中。通过调用即可使用。
func main(){
var ops uint64 = 0 // 定义一个计数器
for i:=0;i<50;i++{
go func() {
for{
atomic.AddUint64(&ops,1) // 进行一次加一操作
runtime.Gosched() // 不影响其他协程的运行
}
}()
}
time.Sleep(time.Second) // 模拟间隔时间
opsFinal := atomic.LoadUint64(&ops) // 为了计数器被其他协程更新时,安全使用,可以使用拷贝的方法将计数器中的值拷贝出来
fmt.Println("ops:",opsFinal)
}
2、互斥锁mutexes
可以使用互斥锁在goroutine
中安全的获取数据。
func main(){
var state = make(map[int]int) // 定义一个map
var mutex = &sync.Mutex{
} // 定义一个锁对象
var ops int64 = 0 // 定义一个计数器,记录对state的操作
for r:=0;r<100;r++{
go func() {
total := 0
for {
key := rand.Intn(5) // 随机获取key的值
mutex.Lock() // 打开锁
total += state[key] // 将state的值传给total
mutex.Unlock() // 关闭锁
atomic.AddInt64(&ops,1) // 计数器+1
runtime.Gosched() // 保证不出现锁饿死的现象
}
}()
}
for w:=0;w<10;w++{
go func() {
key := rand.Intn(5) // 随机获取key的值
val := rand.Intn(100) // 随机获取val的值
mutex.Lock() // 打开锁
state[key] = val // 给state赋值
mutex.Unlock() // 关闭锁
atomic.AddInt64(&ops,1) // 计数器+1
runtime.Gosched() // 保证不出现死锁情况
}()
}
time.Sleep(time.Second) // 模拟间隔时间
opsFinal := atomic.LoadInt64(&ops) // 获取ops的值
fmt.Println("ops:",opsFinal) // 输出ops的值
mutex.Lock() // 打开锁
fmt.Println("state:",state) // 输出state的值
mutex.Unlock() // 关闭锁
}
3、Go状态协程stateful-goroutins
使用goroutine
和channel
实现共享资源跨多个goroutine
同步访问。
type readOp struct {
key int
resp chan int
}
type writeOp struct {
key int
val int
resp chan bool
}
func main(){
var ops int64 // 定义计数器
reads := make(chan *readOp) // 定义readOp类的通道
writes := make(chan *writeOp) // 定义writeOp类的通道
go func() {
// 在协程中执行
var state = make(map[int]int) // 定义map
for {
select {
// 通道选择器
case read := <- reads: // 接收来自reads通道中的数据
read.resp <- state[read.key] // 向readOp的resp通道中发送数据
case write := <- writes: // 接收来自writes通道中的数据
state[write.key] = write.val // 键值对复制
write.resp <- true // 向writeOp的resp通道中发送数据
}
}
}()
for r:=0;r<100;r++{
// 模拟在readOp中操作
go func() {
for {
read := &readOp{
// 创建实例
key: rand.Intn(5),
resp: make(chan int),
}
reads <- read // 向reads通道中发送数据
<- read.resp // 接收数据
atomic.AddInt64(&ops,1) // 计数器+1,
}
}()
}
time.Sleep(time.Second) // 协程运行1秒
opsFinal1 := atomic.LoadInt64(&ops) // 获取计数器的值,协程运行的次数
fmt.Println("ops1:",opsFinal1)
for w:=0;w<10;w++{
go func() {
for {
write := &writeOp{
// 创建实例
key: rand.Intn(5),
val: rand.Intn(5),
resp:make(chan bool),
}
writes <- write // 向writes通道发送数据
<-write.resp // 接收数据
atomic.AddInt64(&ops,1) // 计数器+1
}
}()
}
time.Sleep(time.Second) // 协程运行1秒
opsFinal2 := atomic.LoadInt64(&ops) // 获取计数器的值,协程运行的次数
fmt.Println("ops2:",opsFinal2)
}