Golang context使用經典案例

2021-03-02 嗨客網IT教程

go 伺服器中,對於每個請求的 request 都是在單獨的 goroutine 中進行的,處理一個 request 也可能涉及多個 goroutine 之間的交互, 使用 context 可以使開發者方便的在這些 goroutine 裡傳遞 request 相關的數據、取消 goroutine 的 signal 或截止日期。

結構
229  func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {230      c := newCancelCtx(parent)231      propagateCancel(parent, &c)232      return &c, func() { c.cancel(true, Canceled) }233  }234  235  236  func newCancelCtx(parent Context) cancelCtx {237      return cancelCtx{238          Context: parent,239          done:    make(chan struct{}),240      }241  }

案例
package main
import ( "context" "fmt")
func main() { fmt.Println("嗨客網(www.haicoder.net)")
gen := func(ctx context.Context) <-chan int { dst := make(chan int) n := 1 go func() { for { select { case <-ctx.Done(): return case dst <- n: n++ } } }() return dst }
ctx, cancel := context.WithCancel(context.Background())  defer cancel()   for n := range gen(ctx) { fmt.Println("Received", n) if n == 5 { break } }}

運行後,如下圖所示:

結構
369  func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {370      if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {371          372          return WithCancel(parent)373      }374      c := &timerCtx{375          cancelCtx: newCancelCtx(parent),376          deadline:  deadline,377      }

案例
package main
import ( "context" "fmt" "time")
func main() { fmt.Println("嗨客網(www.haicoder.net)")
d := time.Now().Add(50 * time.Millisecond) ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println("Context Done,", ctx.Err()) }}

運行後,如下圖所示:

可以清晰的看到,當派生出的子 Context 的 deadline 在父 Context 之後,直接返回了一個父 Context 的拷貝。故語義上等效為父。

WithDeadline 的最後期限調整為不晚於 d 返回父上下文的副本。如果父母的截止日期已經早於 d,WithDeadline (父,d) 是在語義上等效為父。返回的上下文完成的通道關閉的最後期限期滿後,返回的取消函數調用時,或當父上下文完成的通道關閉,以先發生者為準。

結構
436  func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {437      return WithDeadline(parent, time.Now().Add(timeout))438  }

案例
package main
import ( "context" "fmt" "time")
func main() { fmt.Println("嗨客網(www.haicoder.net)")
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel()
select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println("Context Timeout", ctx.Err()) }}

運行後,如下圖所示:

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

結構
454  func WithValue(parent Context, key, val interface{}) Context {454      if key == nil {455          panic("nil key")456      }457      if !reflect.TypeOf(key).Comparable() {458          panic("key is not comparable")459      }460      return &valueCtx{parent, key, val}461  }

案例
package main
import ( "context" "fmt")
func main() { fmt.Println("嗨客網(www.haicoder.net)")
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"))}

運行後,如下圖所示:

WithValue 返回的父與鍵關聯的值在 val 的副本。使用上下文值僅為過渡進程和 Api 的請求範圍的數據,而不是將可選參數傳遞給函數。

提供的鍵必須是可比性和應該不是字符串類型或任何其他內置的類型以避免包使用的上下文之間的碰撞。WithValue 用戶應該定義自己的鍵的類型。為了避免分配分配給接口 {} 時,上下文鍵經常有具體類型結構 {}。另外,導出的上下文關鍵變量靜態類型應該是一個指針或接口。

在 go 伺服器中,對於每個請求的 request 都是在單獨的 goroutine 中進行的,處理一個 request 也可能涉及多個 goroutine 之間的交互, 使用 context 可以使開發者方便的在這些 goroutine 裡傳遞 request 相關的數據、取消 goroutine 的 signal 或截止日期。


相關焦點

  • golang之context使用
    背景golang中並發編程的三種實現方式:chan管道、waitGroup和Context。本篇將重點介紹context的使用,告訴大家基本的使用方式,做到會用。Context概念介紹context譯為上下文,golang在1.6.2的時候還沒有自己的context,在1.7的版本中就把golang.org/x/net/context包被加入到了官方的庫中。golang 的 Context包,是專門用來處理多個goroutine之間與請求域的數據、取消信號、截止時間等相關操作。
  • golang中Context的使用場景
    golang中Context的使用場景context在Go1.7之後就進入標準庫中了。它主要的用處如果用一句話來說,是在於控制goroutine的生命周期。當一個計算任務被goroutine承接了之後,由於某種原因(超時,或者強制退出)我們希望中止這個goroutine的計算任務,那麼就用得到這個Context了。
  • 理解 Golang Context 機制
    【導讀】golang編程中經常用到Context,理解context設計和掌握其機制,對實現我們需要的功能有很大幫助。本文詳細介紹了go Context。1.golang.org/x/net/context包就是這種機制的實現。context包實現的主要功能為:其一,在程序單元之間共享狀態變量。
  • 【Golang】Context基礎篇
    一個接口golang的context包定義了Context類型,根據官方文檔的說法,該類型被設計用來在API邊界之間以及過程之間傳遞截止時間
  • Golang context你必須要知道的
    go1.6 及之前版本請使用 golang.org/x/net/context。go1.7 及之後已移到標準庫 context。func DoSomething(ctx context.Context,arg Arg)error { // ... use ctx ... }即使函數允許,也不要傳入 nil 的 Context。如果不知道用哪種 Context,可以使用 context.TODO()。
  • 走進Golang之Context的使用
    Golang 為我們準備好了一切,就是 context.Context 這個包,這個包的原始碼非常簡單,源碼部分本文會略過,下期單獨一篇文章來講,本篇我們重點談正確的使用。Context 的結構非常簡單,它是一個接口。
  • gRPC 實操指南(golang)
    •C/S架構的傳輸業務,如股票軟體,每天需要用戶登陸的時候去伺服器拉取最新的數據,或者較簡單的文件傳輸業務,登陸驗證業務,證書業務都可以使用rpc的方式•跨語言開發的項目,比如web業務使用golang進行開發,底層使用cpp或c,部分腳本使用py,跨語言通信可以通過RPC提供的不同語言的開發機制進行實現。
  • Golang後臺單元測試實踐
    Golang單測框架選型 & 示例主要介紹golang原生testing框架、testify框架、goconvey框架,看一下哪種框架是結合業務體驗更好的。golang原生testing框架特點文件形式:文件以_test.go 結尾函數形式:func TestXxx(*testing.T)斷言:使用 t.Errorf 或相關方法來發出失敗信號運行:使用go test –v執行單元測試示例// 原函數 (in add.go)func
  • 使用Golang快速構建WEB應用
    如果發現問題或者有好的建議請回復我我回及時更正。 1.Abstract在學習web開發的過程中會遇到很多困難,因此寫了一篇類似綜述類的文章。作為路線圖從web開發要素的index出發來介紹golang開發的學習流程以及Example代碼。在描述中多是使用代碼來描述使用方法不會做過多的說明。最後可以方便的copy代碼來實現自己的需求。
  • golang下文件鎖的使用
    前言題目是golang下文件鎖的使用,但本文的目的其實是通過golang下的文件鎖的使用方法,來一窺文件鎖背後的機制。
  • Golang入門教程——map篇
    今天是golang專題的第7篇文章,我們來聊聊golang當中map的用法。map這個數據結構我們經常使用,存儲的是key-value的鍵值對。在C++/java當中叫做map,在Python中叫做dict。
  • 更便捷的goroutine控制利器- Context
    let『s GO在本文中,我首先會介紹context是什麼,它有什麼作用,以及如何使用,其中還會參雜一點個人的理解,以及部分源碼的了解。What are you waiting for?上下文可以安全地被多個goroutine同時使用巴拉巴拉,說了一大堆,反正我一句沒懂,當然我知道context是幹嘛的,(尬~,不小心暴露了,學渣的本質),說說我的理解以及使用建議對伺服器的傳入請求應創建一個Context,而對伺服器的傳出響應也應接受一個Context。
  • Golang入門教程——面向對象篇
    golang作為一門剛剛誕生十年的新興語言自然是支持面向對象的,但是golang當中面向對象的概念和特性與我們之前熟悉的大部分語言都不盡相同。比如Java、Python等,相比之下, golang這個部分的設計非常得簡潔和優雅(仁者見仁),所以即使你之前沒有系統地了解過面向對象,也沒有關係,也一定能夠看懂。
  • 「Golang」for range 使用方法及避坑指南
    來看看語法糖在我們的Go編寫的業務邏輯中,常用的循環方式,為經典的三段式循環,即for i := 0; i < N; i++ {},這種循環可以幫我們方便的遍歷數組,切片等數據結構,還可以輕鬆的進行一定次數循環的操作,那麼當我們想要遍歷map和channel時,該如何呢?
  • Golang入門教程——基本操作篇
    首先是func關鍵字,我們使用這個關鍵字定義一個函數,之後跟著的是函數名,然後是函數的傳參,最後是函數的返回值。這個順序可能和我們之前普遍接觸的語法不太一樣,例如C++當中是把函數返回類型寫在最前面,然後是函數名和傳參。再比如Python當中則是沒有返回值的任何信息,只有def關鍵字和函數名以及傳入的參數。
  • 【Golang】圖解channel之數據結構
    channel被設計用來實現goroutine間的通信,按照golang的設計思想:以通信的方式共享內存。
  • GoHub 更新至 0.6,在線 Golang 文檔閱讀
    GoHub 使用 Github REST API v3 提供在線 Golang 文檔閱讀.支持兩種結構:Object 單個文檔項目, 多個 Package 組成Array 文檔項目列表, 每個項目的地址和說明, 每個項目下必須有 golist.json例: 單個文檔項目, 使用 GoDocu 生成.
  • Golang語言標準庫 sync 包的 Once 怎麼使用?
    02基本用法Once 的使用也非常簡單,Once 只有一個 Do 方法,接收一個無參數無返回值的函數類型的參數 f,不管調用多少次 Do 方法,參數 f 只在第一次調用 Do 方法時執行。代碼示例:05總結本文開篇介紹了 Once 的官方定義和使用場景,然後結合示例代碼,介紹了 Once 的基本使用,並通過閱讀源碼,介紹了 Once 的實現原理,最後列舉了一個容易踩的「坑」。
  • 聊聊golang的defer
    序本文主要研究一下golang的deferdeferreturn先賦值(對於命名返回值),然後執行defer,最後函數返回
  • golang基礎語法
    golang基礎語法Go 程序可以由多個標記組成,可以是關鍵字,標識符,常量,字符串,符號。