一.在Go語言中有兩種較為優(yōu)雅的方式退出goroutine
1.使用自定義channel通知goroutine退出跑慕。
2.使用context傳遞上下文通知goroutine退出问裕。(官方推薦厉熟;本質(zhì)上也是通過channel通知)
自定義channel版本:
package main
import (
"fmt"
"time"
)
//如何優(yōu)雅地退出goroutine
//1.使用自定義channel版本
func worker(exit_ch chan struct{}){
for{
fmt.Println("worker")
time.Sleep(time.Second*1)
select{
case <-exit_ch:
return
default:
}
}
}
func main() {
exit_ch := make(chan struct{})
go worker(exit_ch)
time.Sleep(time.Second*5)
exit_ch<-struct{}{}
close(exit_ch)
fmt.Println("over")
}
官方版本:
官方推薦版本荷腊,明顯是優(yōu)于自定義channel版本素征,因為官方context里面已經(jīng)統(tǒng)一為我們定義了channel环凿;更重要的是梧兼,使用context我們可以取消多個goroutine,下面代碼中我們在worker中新開了一個worker2的goruntine智听,調(diào)用cancel也會通知worker2退出羽杰。
package main
import "fmt"
import "time"
import "context"
func worker(ctx context.Context) {
go worker2(ctx)//在子go中再開一個go,傳入ctx
LOOP:
for {
fmt.Println("worker")
time.Sleep(time.Second)
select {
case <-ctx.Done(): // 等待上級通知
break LOOP
default:
}
}
}
//主線程調(diào)用cancle()到推,worker2也能收到通知退出考赛。
func worker2(ctx context.Context){
LOOP:
for {
fmt.Println("worker2")
time.Sleep(time.Second)
select {
case <-ctx.Done(): // 等待cancel通知
break LOOP//跳出外層循環(huán)
default:
}
}
}
func main() {
ctx,cancel := context.WithCancel(context.Background())
go worker(ctx)
time.Sleep(time.Second*5)
//通知子goroutine
cancel()
fmt.Println("cancel")
time.Sleep(time.Second*5)
fmt.Println("over")
}