一、signal包
1、Notify函数
func Notify(c chan<- os.Signal, sig ...os.Signal)
说明:Notify函数让signal包将输入信号转发到c。如果没有列出要传递的信号,会将所有输入信号传递到c;否则只传递列出的输入信号。且当c阻塞时(缓冲满了),os的输入信号将被丢弃。
2、Stop函数
func Stop(c chan<- os.Signal)
说明:Stop函数让signal包停止向c转发信号。它会取消之前使用c调用的所有Notify的效果。当Stop返回后,会保证c不再接收到任何信号。
二、signal在Web服务中的应用(优雅的退出服务进程)
1、当服务接收到外部输入的终止信号时,应该保证相应的资源得到释放。
2、首先创建信号的处理器,以及信号集结构体,用于对不同信号实现不同处理,代码示例如下:
type handler func(sig os.Signal, arg interface{}) //处理器函数类型 // 信号集结构体 type sigSet struct { set map[os.Signal]signalHandler } // 注册对应的信号及处理器函数 func (sigs *sigSet) register(s os.Signal, h handler) { if _, found := sigs.m[s]; !found { sigs.m[s] = h } } // 对象相应的信号进行处理操作 func (sigs *sigSet) handle(sig os.Signal, arg interface{}) (err error) { if _, found := sigs.m[sig]; found { sigs.m[sig](sig, arg) //执行指定的处理函数 return nil } else { return fmt.Errorf("no handler for signal %v", sig) } }
3、停止服务器的入口函数
func StopServer(release func()) { sigMap := new(sigSet) sigMap.set = make(map[os.Signal]signalHandler) Handler := func(sig os.Signal, arg interface{}) { release() //释放资源,并开始退出程序 os.Exit(0) } sigMap.register(syscall.SIGINT, Handler) //注册ctrl+c的外部输入信号,可注册多个其他信号及处理函数 // 循环等待外部输入信号 for { s := make(chan os.Signal) signal.Notify(s) //将外部输入信号都传递给s管道 sig := <-s //阻塞,直至s中管道有信号 err := sig.handle(sig, nil) if err != nil { fmt.Errorf("unknown signal received %v", sig) } } }
4、主函数的实现,创建一个goruotine来执行服务器停止函数
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) stop := make(chan bool, 1) go StopServer( func() { service.Stop() //关闭与存储相关的连接资源 stop <- true }) service.Start() //启动相关web服务 <- stop //阻塞,直到stop管道被赋值 fmt.Println("service is over") }