在线文档  >   Golang练习   >   信号

有时我们希望我们的 Go 程序能够智能地处理 Unix 信号。例如,我们可能希望服务器在接收到 SIGTERM 时优雅地关闭,或者命令行工具在接收到 SIGINT时停止处理输入。

以下是如何使用通道在 Go 中处理信号。

package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

func main() {

    // Go 的信号通知通过在通道上发送 `os.Signal` 值来实现。
    // 我们将创建一个通道来接收这些通知。请注意,此通道应该带缓冲。
    sigs := make(chan os.Signal, 1)

    // `signal.Notify` 函数将指定的信号注册给给定的通道进行接收通知。
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

    // 我们可以在这里的 main 函数中从 `sigs` 接收信号,
    // 但让我们看看如何在单独的 goroutine 中执行此操作,以演示更逼真的场景,即优雅关机。
    done := make(chan bool, 1)

    go func() {
        // 此 goroutine 执行阻塞接收信号。
        // 当它收到信号时,它会将其打印出来,并通知程序可以完成了。
        sig := <-sigs
        fmt.Println()
        fmt.Println(sig)
        done <- true
    }()

    // 程序将在此处等待,直到获取到期望的信号(如上述 goroutine 向 `done` 发送值所示),然后退出。
    fmt.Println("awaiting signal")
    <-done
    fmt.Println("exiting")
}

运行结果如下:

当我们运行这个程序时,它将一直等待一个信号。 通过 ctrl-C(终端显示为 ^C),我们可以发送一个 SIGINT 信号, 这会使程序打印 interrupt 然后退出。

$ go run signals.go
awaiting signal
^C
interrupt
exiting