最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Go語言如何熱重載和優(yōu)雅地關閉程序

 更新時間:2023年07月16日 09:14:42   作者:242030  
我們有時會因不同的目的去關閉服務,一種關閉服務是終止操作系統(tǒng),一種關閉服務是用來更新配置,本文就來和大家簡單講講這兩種方法的實現(xiàn)吧

我們有時會因不同的目的去關閉服務,一種關閉服務是終止操作系統(tǒng),一種關閉服務是用來更新配置。

我們希望優(yōu)雅地關閉服務和通過熱重載重新加載配置,而這兩種方式可以通過信號包來完成。

1、代碼實現(xiàn)

package main
import (
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
)
type Config struct {
	Message string
}
var conf = &Config{Message: "Before hot reload"}
func router() {
	log.Println("starting up....")
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(conf.Message))
	})
	go func() {
		log.Fatal(http.ListenAndServe(":8080", nil))
	}()
}
func main() {
	router()
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
	for {
		multiSignalHandler(<-sigCh)
	}
}
func multiSignalHandler(signal os.Signal) {
	switch signal {
	case syscall.SIGHUP:
		log.Println("Signal:", signal.String())
		log.Println("After hot reload")
		conf.Message = "Hot reload has been finished."
	case syscall.SIGINT:
		log.Println("Signal:", signal.String())
		log.Println("Interrupt by Ctrl+C")
		os.Exit(0)
	case syscall.SIGTERM:
		log.Println("Signal:", signal.String())
		log.Println("Process is killed.")
		os.Exit(0)
	default:
		log.Println("Unhandled/unknown signal")
	}
}

首先,定義了一個 Config 結構并聲明了一個 conf 變量。

type Config struct {
	Message string
}
var conf = &Config{Message: "Before hot reload"}

這里的代碼只是一個簡單的配置樣本,你可以根據(jù)自己的需要定義一個復雜的結構。

其次,定義一個路由器函數(shù),用來綁定和監(jiān)聽 8080 端口。在熱重載配置完成后,它也被用來顯示結果。

func router() {
    log.Println("starting up....")
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        _, _ = w.Write([]byte(conf.Message))
    })
    go func() {
        log.Fatal(http.ListenAndServe(":8080", nil))
    }()
}

下一步是服務器關機和熱重載配置,當一個服務器關閉時,它應該停止接收新的請求,同時完成正在進行的請求,

返回其響應,然后關閉,在這里使用信號包實現(xiàn)。

sigCh := make(chan os.Signal, 1)

之后,使用 signal.Notify() 一起發(fā)送更多的信號。

signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)

當程序被中斷時,signal.Notify 將向 sigCh 通道發(fā)送一個信號。

syscall.SIGHUP、syscall.SIGINT 和 syscall.SIGTERM 是什么意思?

  • syscall.SIGINT 是用來在 Ctrl+C 時優(yōu)雅地關閉的,它也相當于 os.Interrupt。
  • syscall.SIGTERM 是常用的終止信號,也是 docker 容器的默認信號,Kubernetes 也使用它。
  • syscall.SIGHUP 用于熱重載配置。

如何優(yōu)雅地關閉,multiSignalHandler(<-sigCh) 被用來接收 chan 值,然后它將決定運行代碼的哪一部分。

func multiSignalHandler(signal os.Signal) {
    switch signal {
    case syscall.SIGHUP:
        log.Println("Signal:", signal.String())
        log.Println("After hot reload")
        conf.Message = "Hot reload has been finished."
    case syscall.SIGINT:
        log.Println("Signal:", signal.String())
        log.Println("Interrupt by Ctrl+C")
        os.Exit(0)
    case syscall.SIGTERM:
        log.Println("Signal:", signal.String())
        log.Println("Process is killed.")
        os.Exit(0)
    default:
        log.Println("Unhandled/unknown signal")
    }
}

2、測試優(yōu)雅關閉

首先,運行服務器。

$ go run main.go
2023/06/25 09:57:05 starting up....

發(fā)送一個curl請求。

$ curl localhost:8080
Before hot reload

先用Ctrl+C測試一下中斷。

$ go run main.go
2023/06/25 09:57:05 starting up....
2023/06/25 09:59:45 Signal: interrupt
2023/06/25 09:59:45 Interrupt by Ctrl+C

3、熱重載

首先,運行服務器。

$ go run main.go
2023/06/24 22:03:17 starting up....

然后,發(fā)送curl請求。

$ curl localhost:8080
Before hot reload

查看進程:

$ lsof -i tcp:8080
COMMAND   PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
main    85193 root    3u  IPv6 13642377      0t0  TCP *:webcache (LISTEN)

使用 kill 殺死進程:

$ kill -SIGHUP 85193

$ go run main.go
2023/06/24 22:03:17 starting up....
2023/06/24 22:06:05 Signal: hangup
2023/06/24 22:06:05 After hot reload

如果直接使用 kill 命令殺死程序:

$ go run main.go
2023/06/24 22:14:11 starting up....

$ lsof -i tcp:8080
COMMAND   PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
main    89619 root    3u  IPv6 13669401      0t0  TCP *:webcache (LISTEN)

$ kill -9 89619

$ go run main.go
2023/06/24 22:14:11 starting up....
2023/06/24 22:14:50 Signal: terminated
2023/06/24 22:14:50 Process is killed.

4、Go信號庫os/signal

在官方介紹中,這個庫主要封裝信號實現(xiàn)對輸入信號的訪問,信號主要用于類 Unix 系統(tǒng)。

信號是事件發(fā)生時對進程的通知機制,有時也稱之為軟件中斷。信號與硬件中斷的相似之處在于打斷了程序執(zhí)行的正常流程,大多數(shù)情況下,無法預測信號到達的精確時間。

因為一個具有合適權限的進程可以向另一個進程發(fā)送信號,這可以稱為進程間的一種同步技術。當然,進程也可以向自身發(fā)送信號。然而,發(fā)往進程的諸多信號,通常都是源于內核。引發(fā)內核為進程產生信號的各類事件如下:

硬件發(fā)生異常,即硬件檢測到一個錯誤條件并通知內核,隨即再由內核發(fā)送相應信號給相關進程。比如執(zhí)行一條異常的機器語言指令(除0,引用無法訪問的內存區(qū)域)。

用戶鍵入了能夠產生信號的終端特殊字符。如中斷字符 (通常是 Control-C)、暫停字符(通常是 Control-Z)。

發(fā)生了軟件事件。如調整了終端窗口大小,定時器到期等。

4.1 舉例說明

package main
import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
)
func main() {
	// os.Signal是一個系統(tǒng)信號接收channel
	c := make(chan os.Signal, 1)
	// syscall都是一些系統(tǒng)信號
	signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
	for {
		s := <-c
		fmt.Printf("get a signal %s", s.String())
		switch s {
		case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
			fmt.Printf("exit")
			os.Exit(0)
		case syscall.SIGHUP:
			fmt.Printf("reload")
		default:
			fmt.Printf("nothing")
		}
	}
}

1、首先初始化一個 os.Signal 類型的 channel,我們必須使用緩沖通道,否則在信號發(fā)送時如果還沒有準備好接收信號,就有丟失信號的風險。

2、signal.notify 用于監(jiān)聽信號,參數(shù)1表示接收信號的 channel,參數(shù)2及后面的表示要監(jiān)聽的信號:

  • syscall.SIGHUP 表示終端控制進程結束
  • syscall.SIGQUIT 表示用戶發(fā)送QUIT字符 (Ctrl+/) 觸發(fā)
  • syscall.SIGTERM 表示結束進程
  • syscall.SIGINT 表示用戶發(fā)送INTR字符 (Ctrl+C) 觸發(fā)

3、<-c 一直阻塞直到接收到信號退出。

對于上面的的程序是優(yōu)雅的退出守護進程,接下來就是一些釋放資源或dump進程當前狀態(tài)或記錄日志的動作,完成這些后,主進程退出。

4.2 GO的信號類型

4.2.1 POSIX.1-1990標準中定義的信號列表

4.2.2 在SUSv2和POSIX.1-2001標準中的信號列表

信號 SIGKILL 和 SIGSTOP 可能不會被程序捕獲,因此不會受此軟件包影響。

同步信號是由程序執(zhí)行中的錯誤觸發(fā)的信號:SIGBUS,SIGFPE 和 SIGSEGV。這些只在程序執(zhí)行時才被認為是同步的,而不是在使用 os.Process.Kill 或 kill 程序或類似的機制發(fā)送時。一般來說,除了如下所述,Go 程序會將同步信號轉換為運行時異常。其余信號是異步信號,它們不是由程序錯誤觸發(fā)的,而是從內核或其他程序發(fā)送的。

在異步信號中,SIGHUP 信號在程序失去其控制終端時發(fā)送。當控制終端的用戶按下中斷字符(默認為^ C

(Control-C))時,發(fā)送 SIGINT 信號。當控制終端的用戶按下退出字符時發(fā)送 SIGQUIT 信號,默認為^ \

(Control-Backslash)。一般情況下,您可以通過按^ C來使程序簡單地退出,并且可以通過按^使堆棧轉儲退出。

4.3 Kill命令的原理

我們平時在 Linux 系統(tǒng)會 kill 命令來殺死進程,那其中的原理是什么呢。

4.3.1 kill pid

kill pid 的作用是向進程號為 pid 的進程發(fā)送 SIGTERM (這是 kill 默認發(fā)送的信號),該信號是一個結束進程的信號且可以被應用程序捕獲。若應用程序沒有捕獲并響應該信號的邏輯代碼,則該信號的默認動作是 kill 掉進程。這是終止指定進程的推薦做法。

4.3.2 kill -9 pid

kill -9 pid 則是向進程號為 pid 的進程發(fā)送 SIGKILL (該信號的編號為9),從本文上面的說明可知,SIGKILL 既不能被應用程序捕獲,也不能被阻塞或忽略,其動作是立即結束指定進程。通俗地說,應用程序根本無法感知 SIGKILL信號,它在完全無準備的情況下,就被收到 SIGKILL 信號的操作系統(tǒng)給干掉了,顯然,在這種暴力情況下,應用程序完全沒有釋放當前占用資源的機會。事實上,SIGKILL 信號是直接發(fā)給 init 進程的,它收到該信號后,負責終止 pid 指定的進程。在某些情況下(如進程已經 hang 死,無響應正常信號),就可以使用 kill -9 來結束進程。

到此這篇關于詳解Go語言如何熱重載和優(yōu)雅地關閉程序的文章就介紹到這了,更多相關Go語言優(yōu)雅關閉程序內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 詳解Go語言中Validator庫的使用方法和用途

    詳解Go語言中Validator庫的使用方法和用途

    github.com/go-playground/validator 是一個 Go 語言的庫,用于對結構體字段進行驗證,它提供了一種簡單而靈活的方式來定義驗證規(guī)則,在這篇文章中,我們將從一個簡單的問題出發(fā),帶你了解 Validator 庫的用途,也會介紹Validator 的基本使用
    2023-09-09
  • Go語言題解LeetCode561數(shù)組拆分

    Go語言題解LeetCode561數(shù)組拆分

    這篇文章主要為大家介紹了Go語言題解LeetCode561數(shù)組拆分示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • Golang中的map操作方法詳解

    Golang中的map操作方法詳解

    這篇文章主要給大家介紹了關于Golang中map操作方法的相關資料,map是一種無序的基于key-value的數(shù)據(jù)結構,Go語言中map是引用類型,必須初始化才能使用,需要的朋友可以參考下
    2023-11-11
  • 一文帶你學會Go?select語句輕松實現(xiàn)高效并發(fā)

    一文帶你學會Go?select語句輕松實現(xiàn)高效并發(fā)

    這篇文章主要為大家詳細介紹了Golang中select語句的用法,文中的示例代碼講解詳細,對我們學習Golang有一定的幫助,需要的可以參考一下
    2023-03-03
  • 手把手帶你走進Go語言之常量解析

    手把手帶你走進Go語言之常量解析

    這篇文章主要介紹了Go語言之常量解析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • go語言使用scp的方法實例分析

    go語言使用scp的方法實例分析

    這篇文章主要介紹了go語言使用scp的方法,實例分析了go語言調用scp命令的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • 使用go module導入本地包的方法教程詳解

    使用go module導入本地包的方法教程詳解

    go module 將是Go語言默認的依賴管理工具。到今天 Go1.14 版本推出之后 Go modules 功能已經被正式推薦在生產環(huán)境下使用了。本文重點給大家介紹如何使用 go module 導入本地包,感興趣的朋友一起看看吧
    2020-03-03
  • go語言定時器Timer及Ticker的功能使用示例詳解

    go語言定時器Timer及Ticker的功能使用示例詳解

    這篇文章主要為大家介紹了go語言定時器的功能使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • Go Java算法最大單詞長度乘積示例詳解

    Go Java算法最大單詞長度乘積示例詳解

    這篇文章主要為大家介紹了Go Java算法最大單詞長度乘積示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • go語言阻塞函數(shù)和非阻塞函數(shù)實現(xiàn)

    go語言阻塞函數(shù)和非阻塞函數(shù)實現(xiàn)

    本文主要介紹了go語言阻塞函數(shù)和非阻塞函數(shù)實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03

最新評論

中方县| 长武县| 庆元县| 横峰县| 荣成市| 长宁区| 潼关县| 涡阳县| 从化市| 怀宁县| 澎湖县| 靖宇县| 金平| 信丰县| 辛集市| 柳州市| 辽阳县| 罗田县| 靖边县| 梨树县| 兴山县| 正安县| 河东区| 榆林市| 荔波县| 泸西县| 陇川县| 北流市| 三原县| 威海市| 阜平县| 鹤庆县| 沛县| 吴江市| 承德县| 中方县| 中阳县| 荥经县| 济宁市| 沁源县| 闽侯县|