stop := make(chan bool)
go func() {
for {
select {
case <-stop:
fmt.Println("监控退出,停止了...")
return
default:
fmt.Println("goroutine监控中...")
time.Sleep(2 * time.Second)
}
}
}()
time.Sleep(10 * time.Second)
fmt.Println("可以了,通知监控停止")
stop<- true
//为了检测监控过是否停止,如果没有监控输出,就表示停止了
time.Sleep(5 * time.Second)
以上是使用chan + select 来结束goroutine。但是有弊端:当有多个goroutine需要控制结束就很复杂。
定义一个stop的chan,通知他结束后台goroutine。在后台goroutine中,判断stop是否可以接收到值,如果可以接收到,就表示可以停止退出了,如果没有接收到,就会执行default里面的监控逻辑,极限监控,直到收到stop的通知。
下面使用go的context来实现:
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("监控退出,停止了...")
return
default:
fmt.Println("goroutine监控中...")
time.Sleep(2 * time.Second)
}
}
}(ctx)
time.Sleep(10 * time.Second)
fmt.Println("可以了,通知监控停止")
cancel()
//为了检测监控过是否停止,如果没有监控输出,就表示停止了
time.Sleep(5 * time.Second)
context.Backgroud()返回一个空的Context,这个空的Cobtext一般用于整个Context树的根节点。
使用context.WithCancel(parent)函数,创建一个可取消的子context,当作参数传递给goroutine,这样就可以使用这个子context跟踪这个goroutine。
context控制多个goroutine
func main() {
ctx, cancel := context.WithCancel(context.Background())
go watch(ctx,"【监控1】")
go watch(ctx,"【监控2】")
go watch(ctx,"【监控3】")
time.Sleep(10 * time.Second)
fmt.Println("可以了,通知监控停止")
cancel()
//为了检测监控过是否停止,如果没有监控输出,就表示停止了
time.Sleep(5 * time.Second)
}
func watch(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name,"监控退出,停止了...")
return
default:
fmt.Println(name,"goroutine监控中...")
time.Sleep(2 * time.Second)
}
}
}
转自:https://www.flysnow.org/2017/05/12/go-in-action-go-context.html