问题描述
我这里有一个go例程,需要在上下文到期时从外部go例程中停止该例程。但是,即使上下文控制的go例程停止运行,go例程也不会在上下文到期时停止并继续运行。
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctxParent := context.Background()
ch := make(chan bool)
d := 5 * time.Second
ctx,cancel := context.WithTimeout(ctxParent,d)
defer cancel()
go doSomething(ctx,ch)
// go func() {
select {
// done
case _ = <-ch:
fmt.Println("goroutine finished")
}
fmt.Println("waiting 11 seconds on main thread,ending all go routines")
time.Sleep(11 * time.Second)
fmt.Println(">>>> END")
}
func doSomething(ctx context.Context,ch chan<- bool) {
// how to kill this go routine if context expires??
go func(ctx context.Context) {
fmt.Println("LOTS OF WORK TIME..")
for i := 0; i < 1000; i++ {
time.Sleep(1 * time.Second) // LOTS OF WORK
fmt.Println(i)
}
}(ctx)
select {
case _ = <-ctx.Done():
fmt.Println("*** Go routine timed out in 5 seconds!!! ****")
ch <- true
return
}
}
这将打印(https://play.golang.org/p/L8u51odiHxS)
LOTS OF WORK TIME..
0
1
2
3
4
*** Go routine timed out in 5 seconds!!! ****
goroutine finished
waiting 11 seconds on main thread,ending all go routines
5
6
7
8
9
10
11
12
13
14
15
>>>> END
它不应该打印5,6,7,8 ...等。是否有办法杀死这个内部go例程?
解决方法
您必须在goroutine中检查上下文的过期/取消情况:
defaultData
,
就像Burak Serdar所说,您必须检查goroutine中上下文的状态,而不仅仅是在goroutine的开始时:您必须定期在goroutine中进行检查。
go func(ctx context.Context) {
for i := 0; i < 1000; i++ {
select {
case <-ctx.Done():
return
default:
// do some work
}
}
}(ctx)
一般来讲,不应从外部杀死goroutine;它必须自己检查并意识到时间到了。