• golang signal信号处理


    1、使用场景

    实际项目中,我们希望修改了配置文件后,但又不想通过重启进程让它重新加载配置文件,可以使用signal的方式进行信号传递,或者我们希望通过信号控制,实现一种优雅的退出方式。Golang为我们提供了signal包,实现信号处理机制,允许Go 程序与传入的信号进行交互。

    2、常用的Term信号

    3、简单的栗子

    package main
     
    import (
            "fmt"
            "os"
            "os/signal"
    )
     
    func main() {
            c := make(chan os.Signal)
            signal.Notify(c)
            fmt.Println("start..")
            s := <-c
            fmt.Println("End...", s)
    }

    1)传递SIGINT信号

    [homework@xxxxx signal]$ go run monitor.go
    start..
     
     
     
     
    #此时,CTL+C发送一个SIGINT信号量,得到输出为:
    [homework@xxxxx signal]$ go run monitor.go
    start..
    ^CEnd... interrupt

    (2)传递SIGTERM信号

    打开2个Term窗口
    第一个运行go run monitor.go程序
    第二个执行:ps -ef | grep monitor.go | grep grep -v | awk '{print $2}' | xargs kill
    #此时,kill命令发送一个SIGTERM信号量,得到输出为:
    [homework@xxxxx signal]$ go run monitor.go
    start..
    Terminated

    4、优雅的退出守护进程

    (1)何为优雅(graceful)?

    Linux Server端的应用程序经常会长时间运行,在运行过程中,可能申请了很多系统资源,也可能保存了很多状态。

    在这些场景下,我们希望进程在退出前,可以释放资源或将当前状态dump到磁盘上或打印一些重要的日志,即希望进程优雅退出。

    (2)从对优雅退出的理解不难看出:优雅退出可以通过捕获SIGTERM来实现。

    A、注册SIGTERM信号的处理函数并在处理函数中做一些进程退出的准备,信号处理函数的注册sigaction()来实现。

    B、在主进程的main()中,通过类似于while(!fQuit)的逻辑来检测那个flag变量,一旦fQuit在signal handler function中被置为true,则主进程退出while()循环,接下来就是一些释放资源或dump进程当前状态或记录日志的动作,完成这些后,主进程退出。

    栗子:优雅退出go守护进程

     

    package main
     
    import (
            "fmt"
            "os"
            "os/signal"
            "syscall"
            "time"
    )
     
    func main() {
            //创建监听退出chan
            c := make(chan os.Signal)
            //监听指定信号 ctrl+c kill
            signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, 
                             syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
            go func() {
                    for s := range c {
                            switch s {
                            case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
                                    fmt.Println("Program Exit...", s)
                                    GracefullExit()
                            case syscall.SIGUSR1:
                                    fmt.Println("usr1 signal", s)
                            case syscall.SIGUSR2:
                                    fmt.Println("usr2 signal", s)
                            default:
                                    fmt.Println("other signal", s)
                            }
                    }
            }()
     
            fmt.Println("Program Start...")
            sum := 0
            for {
                    sum++
                    fmt.Println("sum:", sum)
                    time.Sleep(time.Second)
            }
    }
     
    func GracefullExit() {
            fmt.Println("Start Exit...")
            fmt.Println("Execute Clean...")
            fmt.Println("End Exit...")
            os.Exit(0)
    }

    5、信号的订阅

    信号的订阅是通过 channel实现的,每个os.Signal channel 都会收听自己相应的事件集。

    。golang中对信号的处理主要使用os/signal包中的两个方法:一个是notify方法用来监听收到的信号;一个是 stop方法用来取消监听。

    监听信号

    notify方法原型
    func Notify(c chan<- os.Signal, sig ...os.Signal)
    第一个参数表示接收信号的管道
    第二个及后面的参数表示设置要监听的信号,如果不设置表示监听所有的信号。

    Sometimes we'd like our Go programs to intelligently handle Unix signals. For example, we might want a server to gracefully shutdown when it receives a SIGTERM, or a command-line tool stop processing input if it receives a SIGINT. Here's how to handle signals in Go with channels

    package main
    
    import (
        "fmt"
        "os"
        "os/signal"
        "syscall"
    )
    
    func main() {
    
        sigs := make(chan os.Signal, 1)
        done := make(chan bool, 1)
    
        signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
    
        go func() {
            sig := <-sigs
            fmt.Println("")
            fmt.Println(sig)
            done <- true
        }()
    
        fmt.Println("awaiting signal")
        <-done
        fmt.Println("exiting")
    }
  • 相关阅读:
    js原型对象与Java类的比较
    javascript特效--制作背景电子钟(整点时祝贺生日快乐)
    Java web MVC开发模式入门感悟
    重新审视面向对象编程
    10-排序4 统计工龄(20 分)
    基数排序
    表排序
    快速排序
    09-排序3 Insertion or Heap Sort(25 分)
    09-排序2 Insert or Merge(25 分)
  • 原文地址:https://www.cnblogs.com/youxin/p/16096426.html
Copyright © 2020-2023  润新知