以範例學 Go:訊號

有時我們希望我們的 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)

我們可以於主函式中從 sigs 收到 [訊號](https://zh.wikipedia.org/wiki/%E4%B8%80%E7%AC%A6),但是,不妨看看我們如何於獨立的 goroutine 中執行這項工作,以便示範更務實的優雅關閉場景。

    done := make(chan bool, 1)

這個 goroutine 執行封鎖性的訊號接收。當它收到訊號時,它會列印訊號,然後通知程式可以結束執行。

    go func() {
        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

下一個範例:Exit (離開)。