<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Go 語言 context 都能做什么?

      原文鏈接: Go 語言 context 都能做什么?

      很多 Go 項目的源碼,在讀的過程中會發現一個很常見的參數 ctx,而且基本都是作為函數的第一個參數。

      為什么要這么寫呢?這個參數到底有什么用呢?帶著這樣的疑問,我研究了這個參數背后的故事。

      開局一張圖:

      核心是 Context 接口:

      // A Context carries a deadline, cancelation signal, and request-scoped values
      // across API boundaries. Its methods are safe for simultaneous use by multiple
      // goroutines.
      type Context interface {
          // Done returns a channel that is closed when this Context is canceled
          // or times out.
          Done() <-chan struct{}
      
          // Err indicates why this context was canceled, after the Done channel
          // is closed.
          Err() error
      
          // Deadline returns the time when this Context will be canceled, if any.
          Deadline() (deadline time.Time, ok bool)
      
          // Value returns the value associated with key or nil if none.
          Value(key interface{}) interface{}
      }
      

      包含四個方法:

      • Done():返回一個 channel,當 times out 或者調用 cancel 方法時。
      • Err():返回一個錯誤,表示取消 ctx 的原因。
      • Deadline():返回截止時間和一個 bool 值。
      • Value():返回 key 對應的值。

      有四個結構體實現了這個接口,分別是:emptyCtx, cancelCtx, timerCtxvalueCtx

      其中 emptyCtx 是空類型,暴露了兩個方法:

      func Background() Context
      func TODO() Context
      

      一般情況下,會使用 Background() 作為根 ctx,然后在其基礎上再派生出子 ctx。要是不確定使用哪個 ctx,就使用 TODO()

      另外三個也分別暴露了對應的方法:

      func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
      func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
      func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
      func WithValue(parent Context, key, val interface{}) Context
      

      遵循規則

      在使用 Context 時,要遵循以下四點規則:

      1. 不要將 Context 放入結構體,而是應該作為第一個參數傳入,命名為 ctx
      2. 即使函數允許,也不要傳入 nil 的 Context。如果不知道用哪種 Context,可以使用 context.TODO()
      3. 使用 Context 的 Value 相關方法只應該用于在程序和接口中傳遞和請求相關的元數據,不要用它來傳遞一些可選的參數。
      4. 相同的 Context 可以傳遞給不同的 goroutine;Context 是并發安全的。

      WithCancel

      func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
      

      WithCancel 返回帶有新 Done 通道的父級副本。當調用返回的 cancel 函數或關閉父上下文的 Done 通道時,返回的 ctxDone 通道將關閉。

      取消此上下文會釋放與其關聯的資源,因此在此上下文中運行的操作完成后,代碼應立即調用 cancel

      舉個例子:

      這段代碼演示了如何使用可取消上下文來防止 goroutine 泄漏。在函數結束時,由 gen 啟動的 goroutine 將返回而不會泄漏。

      package main
      
      import (
          "context"
          "fmt"
      )
      
      func main() {
          // gen generates integers in a separate goroutine and
          // sends them to the returned channel.
          // The callers of gen need to cancel the context once
          // they are done consuming generated integers not to leak
          // the internal goroutine started by gen.
          gen := func(ctx context.Context) <-chan int {
              dst := make(chan int)
              n := 1
              go func() {
                  for {
                      select {
                      case <-ctx.Done():
                          return // returning not to leak the goroutine
                      case dst <- n:
                          n++
                      }
                  }
              }()
              return dst
          }
      
          ctx, cancel := context.WithCancel(context.Background())
          defer cancel() // cancel when we are finished consuming integers
      
          for n := range gen(ctx) {
              fmt.Println(n)
              if n == 5 {
                  break
              }
          }
      }
      

      輸出:

      1
      2
      3
      4
      5
      

      WithDeadline

      func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
      

      WithDeadline 返回父上下文的副本,并將截止日期調整為不晚于 d。如果父級的截止日期已經早于 d,則 WithDeadline(parent, d) 在語義上等同于 parent

      當截止時間到期、調用返回的取消函數時或當父上下文的 Done 通道關閉時,返回的上下文的 Done 通道將關閉。

      取消此上下文會釋放與其關聯的資源,因此在此上下文中運行的操作完成后,代碼應立即調用取消。

      舉個例子:

      這段代碼傳遞具有截止時間的上下文,來告訴阻塞函數,它應該在到達截止時間時立刻退出。

      package main
      
      import (
          "context"
          "fmt"
          "time"
      )
      
      const shortDuration = 1 * time.Millisecond
      
      func main() {
          d := time.Now().Add(shortDuration)
          ctx, cancel := context.WithDeadline(context.Background(), d)
      
          // Even though ctx will be expired, it is good practice to call its
          // cancellation function in any case. Failure to do so may keep the
          // context and its parent alive longer than necessary.
          defer cancel()
      
          select {
          case <-time.After(1 * time.Second):
              fmt.Println("overslept")
          case <-ctx.Done():
              fmt.Println(ctx.Err())
          }
      }
      

      輸出:

      context deadline exceeded
      

      WithTimeout

      func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
      

      WithTimeout 返回 WithDeadline(parent, time.Now().Add(timeout))

      取消此上下文會釋放與其關聯的資源,因此在此上下文中運行的操作完成后,代碼應立即調用取消。

      舉個例子:

      這段代碼傳遞帶有超時的上下文,以告訴阻塞函數應在超時后退出。

      package main
      
      import (
          "context"
          "fmt"
          "time"
      )
      
      const shortDuration = 1 * time.Millisecond
      
      func main() {
          // Pass a context with a timeout to tell a blocking function that it
          // should abandon its work after the timeout elapses.
          ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
          defer cancel()
      
          select {
          case <-time.After(1 * time.Second):
              fmt.Println("overslept")
          case <-ctx.Done():
              fmt.Println(ctx.Err()) // prints "context deadline exceeded"
          }
      
      }
      

      輸出:

      context deadline exceeded
      

      WithValue

      func WithValue(parent Context, key, val any) Context
      

      WithValue 返回父級的副本,其中與 key 關聯的值為 val

      其中鍵必須是可比較的,并且不應是字符串類型或任何其他內置類型,以避免使用上下文的包之間發生沖突。 WithValue 的用戶應該定義自己的鍵類型。

      為了避免分配給 interface{},上下文鍵通常具有具體的 struct{} 類型。或者,導出的上下文鍵變量的靜態類型應該是指針或接口。

      舉個例子:

      這段代碼演示了如何將值傳遞到上下文以及如何檢索它(如果存在)。

      package main
      
      import (
          "context"
          "fmt"
      )
      
      func main() {
          type favContextKey string
      
          f := func(ctx context.Context, k favContextKey) {
              if v := ctx.Value(k); v != nil {
                  fmt.Println("found value:", v)
                  return
              }
              fmt.Println("key not found:", k)
          }
      
          k := favContextKey("language")
          ctx := context.WithValue(context.Background(), k, "Go")
      
          f(ctx, k)
          f(ctx, favContextKey("color"))
      }
      

      輸出:

      found value: Go
      key not found: color
      

      本文的大部分內容,包括代碼示例都是翻譯自官方文檔,代碼都是經過驗證可以執行的。如果有不是特別清晰的地方,可以直接去讀官方文檔。

      以上就是本文的全部內容,如果覺得還不錯的話歡迎點贊轉發關注,感謝支持。


      官方文檔:

      源碼分析:

      推薦閱讀:

      posted @ 2023-07-02 12:31  yongxinz  閱讀(371)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 吉川爱美一区二区三区视频| 国内免费视频成人精品| 国产中文99视频在线观看| 一本大道无码av天堂| 国产精品成人久久电影| 国产三级黄色片在线观看| 亚洲精品一区国产| 国产在线国偷精品免费看| 国产精品福利在线观看无码卡一| 2019亚洲午夜无码天堂| 国产精品国产三级国av| 久久综合色之久久综合| 无码专区人妻系列日韩精品 | 成人综合人人爽一区二区| 成人国产永久福利看片| 亚洲精品国产一二三区| 男人一天堂精品国产乱码| 中文字幕在线观看一区二区| 亚洲成年av天堂动漫网站| 熟妇人妻任你躁在线视频| 国产91精品调教在线播放| 天堂av在线一区二区| 国产不卡一区二区精品| 男女性高爱潮免费网站| 欧美人成精品网站播放| 大香j蕉75久久精品免费8| 国产精品午夜av福利| 中文字幕人妻中出制服诱惑| 日日噜噜夜夜爽爽| 久久精品国产亚洲AⅤ无码| 国产福利免费在线观看| 少妇人妻偷人精品系列| 色播久久人人爽人人爽人人片av| 国产一区二区av天堂热| 无码视频伊人| 日韩在线视频网| 亚洲精品综合网二三区| 少妇特黄a一区二区三区| 国内自拍偷拍福利视频看看| 国内少妇偷人精品免费| 2019亚洲午夜无码天堂|