从 go routine 外部停止 goroutine
stopping a goroutine from outside the go routine
我这里有一个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 中的上下文 expiration/cancellation:
go func(ctx context.Context) {
fmt.Println("LOTS OF WORK TIME..")
for i := 0; i < 1000; i++ {
select {
case <-ctx.Done():
return
default:
}
time.Sleep(1 * time.Second) // LOTS OF WORK
fmt.Println(i)
}
}(ctx)
正如 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不应该从外面杀掉;它必须自己检查并意识到时间到了。
我这里有一个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 中的上下文 expiration/cancellation:
go func(ctx context.Context) {
fmt.Println("LOTS OF WORK TIME..")
for i := 0; i < 1000; i++ {
select {
case <-ctx.Done():
return
default:
}
time.Sleep(1 * time.Second) // LOTS OF WORK
fmt.Println(i)
}
}(ctx)
正如 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不应该从外面杀掉;它必须自己检查并意识到时间到了。