添加goroutine
//添加一个goroutine
func main(){
go func(){ // 通过go关键字来修饰函数来启动一个gotoutine
fmt.Println(“sub goroutine”)
}() //调用匿名函数
}
计数信号量
wg sync.WaitGroup // go中的计数信号量
wg.Add(2) // 添加两个量
// goroutine中通过调用Done来释放信号量
go func(){
defer wg.Done()
}
func main(){
wg.Wait() //阻塞等待所有goroutine运行完毕
fmt.Println(“all done!”)
}
对共享资源加锁可以来避免竞争
1. 原子函数
原子函数能够以很底层的加锁机制来同步访问整型变量和指针
import sync/atomic
var counter int64
for count:=0;count<3;count++{
// 强制同一时刻只能有一个goroutine来运行并完成加法操作<br /> atomic.AddInt64(&counter,1)// 安全的对conuter加一<br /> /*<br /> atomic.LoadInt64(&varib) // 安全地读一个int64<br /> atomic.StoreInt64(&varib, v) // 安全地写一个int64
*/<br /> runtime.Gosched() //从当前线程退出,让给其他goroutine<br />}
2. 使用互斥锁(mutex)来同步
go 语言提供了两种锁类型sync.Mutex和sync.RWMutex
Mutex 是最简单的锁,比较暴力,当一个goroutine获得Mutex后,其他goroutine只能等到其释放Mutex
RWMutex相对友好些,是经典的单写多读模型,当读锁占用时会阻止写,但不阻止读,也就是多个goroutine可以同时获取读锁(调用RLock() ) ; 而写锁会阻止任何goroutine( 无论读还是写) 进来,相当于独占锁
互斥锁用于在代码上创建一个临界区,保证同一时间只有一个goroutine可以执行这个临界区代码
package main
import (
“fmt”
“runtime”
“sync”
)
var(
counter int
wg sync.WaitGroup
mutex sync.Mutex
)
func main() {
// server := NewServer(“127.0.0.1”, 8888)
// server.Start()
//计数加2,标识要等待两个goroutine
wg.Add(2)
go incCounter(1)
go incCounter(2)
wg.Wait()
fmt.Println(“final counter:”,counter)
}
func incCounter(id int){
defer wg.Done()
for count:=0;count<2;count++{
//统一时刻只允许一个goroutine进入临界区
mutex.Lock()
{
value:=counter
runtime.Gosched()
value++
counter=value
}
mutex.Unlock()//释放锁
}
}
go语言可以通过竞争检测器来编译程序
go build -race