Golang最佳化-優雅退出

Yoger發表於2022-02-16

透過訊號量可以監聽到系統發出的關停,程式意外關閉、退出、重啟等,可以記錄相關資訊和退出前的操作。

系統支援的訊號型別,其中 1~31項為不可靠訊號, 34~64為可靠訊號

1.SIGHUP:當終端斷開時,將傳送該訊號給終端控制程式。SIGHUP訊號還可用於守護程式。
2.SIGINT:當使用者鍵入終端中斷字元(如:Ctrl + C)終端驅動程式將傳送該訊號給前臺程式組。該訊號預設行為是終止程式。
3.SIGQUIT:當使用者在鍵盤鍵入退出字元(如Ctrl+\)時,該訊號將發往前臺程式組。預設情況下,該訊號終止程式,並生成可用於除錯的核心轉儲檔案。當程式陷入無限迴圈或者不在響應,使用該訊號很合適。
4.SIGILL:程式試圖非法執行機器語言指令,系統將向該程式傳送該訊號。
5.SIGTRAP:該訊號用來實現斷點除錯功能以及strace命令所執行的跟蹤系統呼叫功能。
6.SIGABRT:當程式呼叫abort函式時,系統向該程式傳送該訊號。預設情況下,該訊號會終止程式,併產生核心轉儲檔案。
7.SIGBUS:匯流排錯誤,表示發生了某種記憶體訪問錯誤。當使用mmap()所建立的記憶體對映時,如果試圖訪問的地址超出了底層記憶體對映檔案的結尾,會產生該錯誤。
8.SIGFPE:在發生致命的算術運算錯誤時發出. 不僅包括浮點運算錯誤, 還包括溢位及除數為0等其它所有的算術的錯誤。
9.SIGKILL:此訊號為必殺訊號,處理器程式無法阻塞、忽略或者捕獲,故而總能殺死程式(殭屍程式除外)。
10.SIGUSR1:使用者自定義訊號,核心絕不會為程式產生該訊號。
11.SIGSEGV:試圖訪問未分配給自己的記憶體, 或試圖往沒有寫許可權的記憶體地址寫資料.
12.SIGUSR2:同SIGUSR1描述。
13.SIGPIPE:當某一程式試圖向管道,FIFO或套接字寫入資訊時,如果這些裝置並無相應的閱讀程式,系統將產生該訊號。(管道破裂)
14.SIGALRM:經呼叫alarm()或setitimer()而設定的實時定時器一旦到期,核心將產生該訊號。
15.SIGTERM:這是用來終止程式的標準訊號,也是kill和killall命令所傳送的預設訊號。使用者經常會使用kil -9顯示向程式傳送SIGKILL訊號,然而這一做法通常是錯誤的。精心設計的應用程式應當為SIGTERM訊號設定處理器程式,以便於其能夠預先清理臨時檔案和釋放資源,做到全身而退。傳送SIGKILL訊號可以殺掉某個程式,從而繞開了SIGTERM的訊號處理程式。因此,總是應該首先嚐試使用SIGTERM訊號來終止程式,而把SIGKILL訊號作為最後手段,去對付那些失控的程式。
16.SIGSTKFLT:linux對該訊號做了定義,但並未加以使用。
17.SIGCHLD:當父程式的某一子程式退出時,核心將向父程式傳送該訊號。
18.SIGCONT:該訊號傳送給已停止的程式,程式將恢復執行。當接收訊號的程式當前處於非停止狀態 時,預設情況下將忽略該訊號。
19.SIFSTOP:程式收到該訊號將停止執行,處理器程式無法將其阻塞、忽略或者捕獲,故而總能停止程式。
20.SIGTSTP:作業控制的停止訊號,當使用者在鍵盤輸入掛起字元(如:Ctrl+Z)時,將傳送該訊號給前臺程式組,使其停止執行。(該訊號可以被處理和忽略)
21.SIGTTIN:在作業控制shell下執行時,若後臺程式組試圖對終端進行read()操作,終端驅動程式則將該程式組傳送該訊號。該訊號預設將停止程式。
22.SIGTTOU:該訊號與SIGTTIN類似,但在寫終端(或修改終端模式)時收到。
23.SIGURG:系統傳送該訊號給一個程式,表示套接字上存在帶外(緊急)資料。
24.SIGXCPU:當程式的CPU時間超出對應的資源限制時,將傳送此訊號給程式。
25.SIGXFSZ:如果程式試圖增大檔案而突破對程式檔案大小的資源限制時,將傳送該訊號給程式。
26.SIGVTALRM:虛擬時鐘訊號. 類似於SIGALRM, 但是計算的是該程式佔用的CPU時間。
27.SIGPROF:類似於SIGALRM/SIGVTALRM, 但包括該程式用的CPU時間以及系統呼叫的時間.
28.SIGWINCH:視窗大小改變時發出該訊號。
29.SIGIO:檔案描述符準備就緒, 可以開始進行輸入/輸出操作。
30.SIGPWR:電源故障訊號。
31.SIGSYS:如果程式發起的系統呼叫有誤,將產生該訊號。

監聽SIGINT和SIGKILL訊號

ctrl+c 產生了一個 SIGINT(中斷訊號)。
kill 9傳送一個 SIGKILL訊號 終止程式的訊號來結束程式。

func main() {
    fmt.Println("start")
    go func() {
        for {
            time.Sleep(time.Second)
            fmt.Println(time.Now().Unix())
        }
    }()
    quit := make(chan os.Signal)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit

    fmt.Println("處理關閉邏輯")
    //......
    fmt.Println("關閉成功")
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章