goroutine同步
互斥锁(sync.Mutex)和读写锁(sync.RWMutex)
类似其他语言,golang也提供了互斥锁和读写锁的的同步原语。
我们先看下go中互斥锁(sync.Mutex)的使用。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
a := 0
for i:=0;i< 100;i++ {
go func() {
a += 1
}()
}
time.Sleep(1e9)
fmt.Println(a)
a = 0
mutex := sync.Mutex{}
for i:=0;i< 100;i++ {
go func() {
mutex.Lock()
defer mutex.Unlock()
a ++
}()
}
time.Sleep(1e9)
fmt.Println(a)
}
$ go run main.go
85
100
我们在看下读写锁(sync.RWMutex)。
读写锁:读的时候不会阻塞读,会阻塞写;写的时候会阻塞写和读,我们可以用这个特性实现线程安全的map。
import "sync"
type safeMap struct {
rwmut sync.RWMutex
Map map[string]int
}
func (sm *safeMap)Read(key string)(int,bool){
sm.rwmut.RLock()
defer sm.rwmut.RUnlock()
if v,found := sm.Map[key];!found {
return 0,false
}else {
return v,true
}
}
func (sm *safeMap)Set(key string,val int) {
sm.rwmut.Lock()
defer sm.rwmut.Unlock()
sm.Map[key] = val
}
WaitGroup
WaitGroup 常用在等goroutine结束。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
wg :=sync.WaitGroup{}
wg.Add(2) //这边说明有2个任务
go func() {
defer wg.Done() //代表任务1结束
time.Sleep(1e9)
fmt.Println("after 1 second")
}()
go func() {
defer wg.Done()//代表任务2结束
time.Sleep(2e9)
fmt.Println("after 2 second")
}()
wg.Wait() //等待所有任务结束
fmt.Println("the end")
}
after 1 second
after 2 second
the end
总结
本小节列举了goroutine使用传统的Mutex
和WaitGroup
做"线程"同步的例子,在go语言中,官方注重推荐使用channel
做“线程”同步,下个小节我们着重介绍channel
的使用。