Goroutine 轻量级线程,goroutine是Go运行时(runtime)管理的协程,比操作系统线程更轻量
初始栈空间只有几kb,会按需自动增长
Go runtime提供M:N调度模型,N个Goroutine映射到M个操作系统线程
在函数调用前加go关键词启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport ( "fmt" "time" ) func work (id int ) { for i:=0 ;i<3 ;i++{ fmt.Printf("Worker %d: %d\n" ,id,i) time.Sleep(time.Millisecond*500 ) } } func main () { go work(1 ) go work(2 ) time.Sleep(2 *time.Second) }
Channel Channel是Go提供的”通信管道”,用于在多个Goroutine之间传递数据
声明与使用如下
1 2 3 4 5 6 7 8 9 package mainimport "fmt" func main () { ch:=make (chan int ,2 ) ch<-10 ch<-20 fmt.Println(<-ch) fmt.Println(<-ch) }
常见模式: 1.生产者-消费者模型 2.任务发布 3.同步信号
Select 多路复用,select语句用来同时监听多个channel的操作,哪一个先准备好就执行哪一个分支
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package mainimport ( "fmt" "time" ) func main () { ch1:=make (chan string ) ch2:=make (chan string ) go func () { time.Sleep(1 *time.Second) ch1<-"Hello from ch1" }() go func () { time.Sleep(2 *time.Second) ch2<-"Hello from ch2" }() for i:=0 ;i<2 ;i++{ select { case msg1:=<-ch1: fmt.Println(msg1) case msg2:<-ch2: fmt.Println(msg2) case <-time.After(1500 *time.Millisecond): fmt.Println("timeout" ) } } }
Context context是Go1.7引入的,用来在Goroutine之间传递取消信号、超时控制、元数据
常见函数:
context.Background():根Context
context.WithCancel():手动取消
context.WithTimeout():超时自动取消
context.WithDeadline():设定截止时间
ctx.Done():返回一个channel,收到信号表示被取消
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package mainimport ( "fmt" "time" "context" ) func worker (ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("worker stopped" ,ctx.Err()) return default : fmt.Println("working..." ) time.Sleep(500 *time.Millisecond) } } } func main () { ctx,cancel:=context.WithTimeout(context.Background(),2 *time.Second) defer cancel() go worker(ctx) time.Sleep(3 *time.Second) }
2秒后ctx自动取消,Goroutine停止
sync.Mutex 互斥锁用于保证同一时间只有一个Goroutine能访问共享资源
并发写共享资源会产生数据竞争,需要加锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport ( "fmt" "sync" ) var ( counter int mu sync.Mutex ) fun add(wg *sync.WaitGroup){ defer wg.Done() for i:=0 ;i<1000 ;i++{ mu.Lock() counter++ mu.Unlock() } } func main () { var wg sync.WaitGroup wg.Add(2 ) go add(&wg) go add(&wg) wg.Wait() fmt.Println("Final counter:" ,counter) }