在實際項目中我們修改了配置文件后,希望在不重啟進程的情況下重新加載配置文件,這時候就需要通過信號傳遞來進行處理了。golang中對信號的處理主要使用os/signal包中的兩個方法:一個是notify方法用來監聽收到的信號;一個是 stop方法用來取消監聽。下面給一個些示例。
監聽信號
notify方法原型
func Notify(c chan<- os.Signal, sig ...os.Signal)
第一個參數表示接收信號的管道
第二個及后面的參數表示設置要監聽的信號,如果不設置表示監聽所有的信號。
package main
import (
"fmt"
"os"
"os/signal"
//"syscall"
)
func main() {
c := make(chan os.Signal)
signal.Notify(c)
//監聽指定信號
//signal.Notify(c, syscall.SIGHUP, syscall.SIGUSR2)
//阻塞直至有信號傳入
s := <-c
fmt.Println("get signal:", s)
}
運行該程序后,搜索到該程序的進程編號,運行kill命令就可以看到信號的輸出。
終端1:
$ go run main.go //此時處於阻塞狀態,當終端2執行kill時輸出如下信息 get signal: user defined signal 2
終端2:
$ ps -ef | grep main 501 839 543 0 11:16PM ttys000 0:00.03 go run main.go 501 842 839 0 11:16PM ttys000 0:00.00 /var/folders/s8/kbqz28xd3wl8q5rw8vsr129c0000gn/T/go-build384577908/command-line-arguments/_obj/exe/main 501 844 709 0 11:16PM ttys001 0:00.00 grep main $ kill -USR2 842
當然這樣的程序在實際中並沒有什么用處,改進一下就可以用來接收信號並且處理一些內容了。
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
go signalListen()
for {
time.Sleep(10 * time.Second)
}
}
func signalListen() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGUSR2)
for {
s := <-c
//收到信號后的處理,這里只是輸出信號內容,可以做一些更有意思的事
fmt.Println("get signal:", s)
}
}
主要就是開啟一個gorutine單獨處理信號的監聽。
停止監聽
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGUSR2)
//當調用了該方法后,下面的for循環內<-c接收到一個信號就退出了。
signal.Stop(c)
for {
s := <-c
fmt.Println("get signal:", s)
}
}
小結
golang中處理信號非常簡單,但是關於信號本身需要了解的還有很多,建議可以參考《Unix高級編程》中的信號篇章。
