为什么 Go 通道阻塞但不退出

Why Go channel is blocking but not quitting

我有这两个版本可以使用 signal.NotifyContext

通过信号实现上下文取消

版本 1 https://play.golang.org/p/rwOnYEgPecE

func main() {
    ch := run()
    <-ch
}

func run() chan bool {
    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
    var done = make(chan bool)

    //go func() {
    select {
    case <-ctx.Done():
        fmt.Println("Quitting")
        stop()
        done <- true
    }
    //}()
    return done
}

版本 2 https://play.golang.org/p/oijbICeSrNT

func main() {
    ch := run()
    <-ch
}

func run() chan bool {
    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
    var done = make(chan bool)

    go func() {
       select {
       case <-ctx.Done():
          fmt.Println("Quitting")
          stop()
          done <- true
       }
    }()
    return done
}

为什么第一个版本打印行 Quitting 但不退出,而第二个版本打印并正确退出?

第一个案例没有像您预期的那样运行的原因是因为一切都运行在单个(主)goroutine 中。

select {
   case <-ctx.Done():
      fmt.Println("Quitting")
      stop()
      done <- true  // this blocks because no one is listening
   }
}

在你的第二个例子中,因为上面的逻辑是 运行 在 goroutine 中,那么 main() 将在频道上监听。

第二种方法是首选,因为任何信号处理程序 - 在程序的生命周期中 运行ning - 应该在其自己的 goroutine 中 运行ning。