<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go1.16 中的新函數(shù) signal.NotifyContext 怎么用?

          共 4110字,需瀏覽 9分鐘

           ·

          2021-06-13 00:41

          閱讀本文大概需要 4 分鐘。

          大家好,我是 polarisxu。

          os/signal 這個(gè)包大家可能用的不多。但自從 Go1.8 起,有些人開始使用這個(gè)包了,原因是 Go1.8 在 net/http 包新增了一個(gè)方法:

          func (srv *Server) Shutdown(ctx context.Context) error

          有了它就不需要借助第三方庫實(shí)現(xiàn)優(yōu)雅關(guān)閉服務(wù)了。具體怎么做呢?

          func main() {
           server = http.Server{
            Addr: ":8080",
           }

           http.HandleFunc("/"func(w http.ResponseWriter, r *http.Request) {
            time.Sleep(time.Second * 10)
            fmt.Fprint(w, "Hello world!")
           })
            
           go server.ListenAndServe()

           // 監(jiān)聽中斷信號(hào)(CTRL + C)
           c := make(chan os.Signal, 1)
           signal.Notify(c, os.Interrupt)
           <-c

           // 重置 os.Interrupt 的默認(rèn)行為
           signal.Reset(os.Interrupt)

           fmt.Println("shutting down gracefully, press Ctrl+C again to force")

           // 給程序最多 5 秒時(shí)間處理正在服務(wù)的請求
           timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
           defer cancel()

           if err := server.Shutdown(timeoutCtx); err != nil {
            fmt.Println(err)
           }
          }
          • 這里利用 os/signal 包監(jiān)聽 Interrupt 信號(hào);
          • 收到該信號(hào)后,16 行 <-c 會(huì)返回;
          • 為了可以再次 CTRL + C 強(qiáng)制退出,通過 Reset 恢復(fù) os.Interrupt 的默認(rèn)行為;(這不是必須的)

          優(yōu)雅退出的關(guān)鍵:1)新請求進(jìn)不來;2)已有請求給時(shí)間處理完。所以,在接收到信號(hào)后,調(diào)用 server.Shutdown 方法,阻止新請求進(jìn)來,同時(shí)給 5 秒等待時(shí)間,讓已經(jīng)進(jìn)來的請求有時(shí)間處理。

          在 Go1.16 中,os/signal 包新增了一個(gè)函數(shù):

          func NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)

          功能和 Notify 類似,但用法上有些不同。上面的例子改用 NotifyContext:

          func after() {
           server = http.Server{
            Addr: ":8080",
           }

           http.HandleFunc("/"func(w http.ResponseWriter, r *http.Request) {
            time.Sleep(time.Second * 10)
            fmt.Fprint(w, "Hello world!")
           })

           go server.ListenAndServe()
           
            // 監(jiān)聽中斷信號(hào)(CTRL + C)
           ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
           <-ctx.Done()

            // 重置 os.Interrupt 的默認(rèn)行為,類似 signal.Reset
           stop()
           fmt.Println("shutting down gracefully, press Ctrl+C again to force")

            // 給程序最多 5 秒時(shí)間處理正在服務(wù)的請求
           timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
           defer cancel()

           if err := server.Shutdown(timeoutCtx); err != nil {
            fmt.Println(err)
           }
          }

          和上面的寫法有區(qū)別,完成的功能一樣的。其實(shí) NotifyContext 的內(nèi)部就是基于 Notify 實(shí)現(xiàn)的:

          func NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) {
           ctx, cancel := context.WithCancel(parent)
           c := &signalCtx{
            Context: ctx,
            cancel:  cancel,
            signals: signals,
           }
           c.ch = make(chan os.Signal, 1)
           Notify(c.ch, c.signals...)
           if ctx.Err() == nil {
            go func() {
             select {
             case <-c.ch:
              c.cancel()
             case <-c.Done():
             }
            }()
           }
           return c, c.stop
          }

          只是在返回的 stop 被調(diào)用時(shí),會(huì)執(zhí)行 os/signal 包中的 Stop 函數(shù),這個(gè) Stop 函數(shù)的功能和 Reset 類似。因此上面 Notify 的例子,Reset 的地方可以改為 Stop。

          從封裝上看,NotifyContext 做的更好。而且,如果在某些需要 Context 的場景下,它把監(jiān)控系統(tǒng)信號(hào)和創(chuàng)建 Context 一步搞定。

          NotifyContext 的用法,優(yōu)雅的關(guān)閉服務(wù),你掌握了嗎?希望你實(shí)際動(dòng)手試驗(yàn)下,啟動(dòng)服務(wù),通過 curl http://localhost:8080/ 訪問,然后按 CTRL + C,看看具體效果。只看不動(dòng)手,基本知識(shí)不是你的。

          關(guān)于 NotifyContext 函數(shù)的文檔可以在這里查看:https://docs.studygolang.com/pkg/os/signal/#NotifyContext。



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號(hào) 「polarisxu」,回復(fù) ebook 獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 63
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  内射无套内射国产精品视频 | 骚逼视频网站 | 精品人妻一区二区三区含羞草 | 久久激情国产 | 操屄的网站 |