<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 怎么用?

          共 4188字,需瀏覽 9分鐘

           ·

          2021-06-06 20:01

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

          大家好,我是 polarisxu。

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

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

          有了它就不需要借助第三方庫(kù)實(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)聽(tīng)中斷信號(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ù)的請(qǐng)求
           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)聽(tīng) Interrupt 信號(hào);
          • 收到該信號(hào)后,16 行 <-c 會(huì)返回;
          • 為了可以再次 CTRL + C 強(qiáng)制退出,通過(guò) Reset 恢復(fù) os.Interrupt 的默認(rèn)行為;(這不是必須的)

          優(yōu)雅退出的關(guān)鍵:1)新請(qǐng)求進(jìn)不來(lái);2)已有請(qǐng)求給時(shí)間處理完。所以,在接收到信號(hào)后,調(diào)用 server.Shutdown 方法,阻止新請(qǐng)求進(jìn)來(lái),同時(shí)給 5 秒等待時(shí)間,讓已經(jīng)進(jìn)來(lái)的請(qǐng)求有時(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)聽(tīng)中斷信號(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ù)的請(qǐng)求
           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 的場(chǎng)景下,它把監(jiān)控系統(tǒng)信號(hào)和創(chuàng)建 Context 一步搞定。

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

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




          往期推薦


          我是 polarisxu,北大碩士畢業(yè),曾在 360 等知名互聯(lián)網(wǎng)公司工作,10多年技術(shù)研發(fā)與架構(gòu)經(jīng)驗(yàn)!2012 年接觸 Go 語(yǔ)言并創(chuàng)建了 Go 語(yǔ)言中文網(wǎng)!著有《Go語(yǔ)言編程之旅》、開(kāi)源圖書《Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)》等。


          堅(jiān)持輸出技術(shù)(包括 Go、Rust 等技術(shù))、職場(chǎng)心得和創(chuàng)業(yè)感悟!歡迎關(guān)注「polarisxu」一起成長(zhǎng)!也歡迎加我微信好友交流:gopherstudio


          瀏覽 81
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  x8x8拨牐拨牐精品视频 | 亚洲精品视频在线观看免费 | 亚洲AV人人澡人人爽人人乐 | 在线无码免费视频 | 天天日天天射一区二区三区 |