从 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不应该从外面杀掉;它必须自己检查并意识到时间到了。