亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

深入Golang之context的用法詳解

2020-04-01 18:58:14
字體:
來源:轉載
供稿:網友

context在Golang的1.7版本之前,是在包golang.org/x/net/context中的,但是后來發現其在很多地方都是需要用到的,所有在1.7開始被列入了Golang的標準庫。Context包專門用來簡化處理單個請求的多個goroutine之間與請求域的數據、取消信號、截止時間等相關操作,那么這篇文章就來看看其用法和實現原理。

源碼分析

首先我們來看一下Context里面核心的幾個數據結構:

Context interface

type Context interface {  Deadline() (deadline time.Time, ok bool)  Done() <-chan struct{}  Err() error  Value(key interface{}) interface{}}

Deadline返回一個time.Time,是當前Context的應該結束的時間,ok表示是否有deadline。

Done方法在Context被取消或超時時返回一個close的channel,close的channel可以作為廣播通知,告訴給context相關的函數要停止當前工作然后返回。

Err方法返回context為什么被取消。

Value可以讓Goroutine共享一些數據,當然獲得數據是協程安全的。但使用這些數據的時候要注意同步,比如返回了一個map,而這個map的讀寫則要加鎖。

canceler interface

canceler interface定義了提供cancel函數的context:

type canceler interface {  cancel(removeFromParent bool, err error)  Done() <-chan struct{}}

其現成的實現有4個:

  1. emptyCtx:空的Context,只實現了Context interface;
  2. cancelCtx:繼承自Context并實現了cancelerinterface
  3. timerCtx:繼承自cancelCtx,可以用來設置timeout;
  4. valueCtx:可以儲存一對鍵值對;

繼承Context

context包提供了一些函數,協助用戶從現有的 Context 對象創建新的 Context 對象。這些Context對象形成一棵樹:當一個 Context對象被取消時,繼承自它的所有Context都會被取消。

Background是所有Context對象樹的根,它不能被取消,它是一個emptyCtx的實例:

var (  background = new(emptyCtx))func Background() Context {  return background}

生成Context的主要方法

WithCancel

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {  c := newCancelCtx(parent)  propagateCancel(parent, &c)  return &c, func() { c.cancel(true, Canceled) }}

返回一個cancelCtx示例,并返回一個函數,可以在外層直接調用cancelCtx.cancel()來取消Context。

WithDeadline

func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {  if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {    return WithCancel(parent)  }  c := &timerCtx{    cancelCtx: newCancelCtx(parent),    deadline: deadline,  }  propagateCancel(parent, c)  d := time.Until(deadline)  if d <= 0 {    c.cancel(true, DeadlineExceeded) // deadline has already passed    return c, func() { c.cancel(true, Canceled) }  }  c.mu.Lock()  defer c.mu.Unlock()  if c.err == nil {    c.timer = time.AfterFunc(d, func() {      c.cancel(true, DeadlineExceeded)    })  }  return c, func() { c.cancel(true, Canceled) }}

返回一個timerCtx示例,設置具體的deadline時間,到達 deadline的時候,后代goroutine退出。

WithTimeout

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {  return WithDeadline(parent, time.Now().Add(timeout))}

和WithDeadline一樣返回一個timerCtx示例,實際上就是WithDeadline包了一層,直接傳入時間的持續時間,結束后退出。

WithValue

func WithValue(parent Context, key, val interface{}) Context {  if key == nil {    panic("nil key")  }  if !reflect.TypeOf(key).Comparable() {    panic("key is not comparable")  }  return &valueCtx{parent, key, val}}

WithValue對應valueCtx ,WithValue是在Context中設置一個 map,這個Context以及它的后代的goroutine都可以拿到map 里的值。

例子

Context的使用最多的地方就是在Golang的web開發中,在http包的Server中,每一個請求在都有一個對應的goroutine去處理。請求處理函數通常會啟動額外的goroutine用來訪問后端服務,比如數據庫和RPC服務。用來處理一個請求的goroutine通常需要訪問一些與請求特定的數據,比如終端用戶的身份認證信息、驗證相關的token、請求的截止時間。 當一個請求被取消或超時時,所有用來處理該請求的 goroutine都應該迅速退出,然后系統才能釋放這些goroutine占用的資源。雖然我們不能從外部殺死某個goroutine,所以我就得讓它自己結束,之前我們用channel+select的方式,來解決這個問題,但是有些場景實現起來比較麻煩,例如由一個請求衍生出的各個 goroutine之間需要滿足一定的約束關系,以實現一些諸如有效期,中止goroutine樹,傳遞請求全局變量之類的功能。

保存上下文

func middleWare(next http.Handler) http.Handler {  return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {    ctx := context.WithValue(req.Context(),"key","value")    next.ServeHTTP(w, req.WithContext(ctx))  })}func handler(w http.ResponseWriter, req *http.Request) {  value := req.Context().Value("value").(string)  fmt.Fprintln(w, "value: ", value)  return}func main() {  http.Handle("/", middleWare(http.HandlerFunc(handler)))  http.ListenAndServe(":8080", nil)}

我們可以在上下文中保存任何的類型的數據,用于在整個請求的生命周期去傳遞使用。

超時控制

func longRunningCalculation(timeCost int)chan string{  result:=make(chan string)  go func (){  time.Sleep(time.Second*(time.Duration(timeCost)))    result<-"Done"  }()  return result}func jobWithTimeoutHandler(w http.ResponseWriter, r * http.Request){  ctx,cancel := context.WithTimeout(context.Background(), 3*time.Second)  defer cancel()  select{  case <-ctx.Done():    log.Println(ctx.Err())    return  case result:=<-longRunningCalculation(5):    io.WriteString(w,result)  }  return}func main() {  http.Handle("/", jobWithTimeoutHandler)  http.ListenAndServe(":8080", nil)}

這里用一個timerCtx來控制一個函數的執行時間,如果超過了這個時間,就會被迫中斷,這樣就可以控制一些時間比較長的操作,例如io,RPC調用等等。

除此之外,還有一個重要的就是cancelCtx的實例用法,可以在多個goroutine里面使用,這樣可以實現信號的廣播功能,具體的例子我這里就不再細說了。

總結

context包通過構建樹型關系的Context,來達到上一層Goroutine能對傳遞給下一層Goroutine的控制??梢詡鬟f一些變量來共享,可以控制超時,還可以控制多個Goroutine的退出。

據說在Google,要求Golang程序員把Context作為第一個參數傳遞給入口請求和出口請求鏈路上的每一個函數。這樣一方面保證了多個團隊開發的Golang項目能夠良好地協作,另一方面它是一種簡單的超時和取消機制,保證了臨界區數據在不同的Golang項目中順利傳遞。

所以善于使用context,對于Golang的開發,特別是web開發,是大有裨益的。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲片在线资源| 5278欧美一区二区三区| 久久综合色88| 45www国产精品网站| 欧美亚洲成人精品| 亚洲第一页在线| 777国产偷窥盗摄精品视频| 一区二区三区黄色| 欧美高清视频一区二区| 91性高湖久久久久久久久_久久99| 欧美日韩在线第一页| 欧美另类极品videosbestfree| 91在线观看免费高清| 久久男人的天堂| 日韩欧美一区二区在线| 亚洲色图18p| 欧美精品18videos性欧| 国产精品专区h在线观看| 亲子乱一区二区三区电影| 国产精品一区二区三| 日韩欧美在线视频| 欧美国产在线视频| 欧美激情一二区| 国产精品成人在线| 欧美大片免费看| 国产91色在线播放| 成人妇女淫片aaaa视频| 91精品国产高清自在线| 亚洲精品一区二区三区婷婷月| 亚洲偷欧美偷国内偷| 青青草原成人在线视频| 国产日韩精品入口| 久久久精品国产一区二区| 欧美黑人一级爽快片淫片高清| 这里只有精品丝袜| 亚洲一区二区久久久久久久| 欧美亚洲另类制服自拍| 亚洲国产精品一区二区久| 亚洲性生活视频在线观看| 国产精品久久久久久亚洲影视| 欧美视频在线观看 亚洲欧| 日韩av中文字幕在线| 久久99精品久久久久久琪琪| 日韩av在线电影网| 亚洲欧美精品中文字幕在线| www.xxxx精品| 日韩av不卡电影| 97视频在线观看播放| 国产亚洲视频在线观看| 国产精品午夜国产小视频| 国产日韩在线视频| 亚洲国产精品99| 国产精品777| 日韩va亚洲va欧洲va国产| 91日本视频在线| 搡老女人一区二区三区视频tv| 国产日韩中文字幕| 国产91九色视频| 视频直播国产精品| 日韩av免费看网站| 成人午夜在线影院| 亚洲成人av中文字幕| 久久久久久久久久婷婷| 国产精品久在线观看| 性日韩欧美在线视频| 亚洲一区二区国产| 久久99热精品这里久久精品| 97国产一区二区精品久久呦| 国产综合久久久久久| 欧美亚洲激情视频| 亚洲韩国欧洲国产日产av| 久久伊人精品天天| 久久综合久久八八| 一区国产精品视频| 8x拔播拔播x8国产精品| 亚洲福利视频久久| zzjj国产精品一区二区| 91sa在线看| 精品久久久精品| 国产区亚洲区欧美区| 97久久精品人人澡人人爽缅北| 中文字幕日韩在线观看| 久久久免费电影| 97avcom| 欧美中文在线观看国产| 久久天天躁狠狠躁夜夜爽蜜月| 在线电影av不卡网址| 久久久免费观看视频| 亚洲欧美在线播放| 精品国产欧美成人夜夜嗨| 国产91在线播放九色快色| 亚洲男子天堂网| 欧美贵妇videos办公室| 国产精品视频永久免费播放| 午夜精品久久久久久久白皮肤| 91成人免费观看网站| 亚洲欧美国产精品| 亚州av一区二区| 国产a级全部精品| 亚洲另类图片色| 97精品欧美一区二区三区| 国产精品视频一区二区高潮| 欧美日韩一区二区三区在线免费观看| 精品人伦一区二区三区蜜桃网站| 国产精品欧美一区二区三区奶水| 亚洲乱亚洲乱妇无码| www.国产精品一二区| 欧美性xxxx极品hd满灌| 亚洲美女视频网站| 中文国产亚洲喷潮| 国产精品专区第二| 日韩在线欧美在线国产在线| 大桥未久av一区二区三区| 亚洲自拍偷拍视频| 国产精品嫩草影院一区二区| 国产一区二中文字幕在线看| 黑人巨大精品欧美一区二区一视频| 亚洲福利在线看| 69久久夜色精品国产69| 精品亚洲夜色av98在线观看| 欧美日韩免费一区| 中文字幕久久久av一区| 午夜精品福利电影| 成人黄色av免费在线观看| 91视频免费在线| 韩日精品中文字幕| 久久综合伊人77777尤物| 欧美国产日韩中文字幕在线| 麻豆国产va免费精品高清在线| 欧美精品videosex牲欧美| 亚洲欧洲国产精品| 日本不卡高字幕在线2019| 欧美一区二区三区免费观看| 国产一区二区三区视频| 欧美一级在线亚洲天堂| 北条麻妃一区二区在线观看| 日韩不卡中文字幕| 久久久久久成人精品| 日韩在线激情视频| 精品久久久久久国产| 91网站在线免费观看| 国产精品福利在线观看| 欧美精品18videosex性欧美| 亚洲午夜精品久久久久久性色| 欧美激情视频一区二区| 成人免费视频在线观看超级碰| 久久久久久久国产| 亚洲无亚洲人成网站77777| 久久成人精品一区二区三区| 91久久久久久久久久久久久| 懂色av影视一区二区三区| 中文字幕在线看视频国产欧美| 亚洲免费伊人电影在线观看av| 亚洲国产精品人久久电影| 91色视频在线观看| 国产在线观看精品| 91国语精品自产拍在线观看性色| 亚洲天堂男人天堂女人天堂| 日韩在线激情视频| 亚洲精品视频网上网址在线观看| 精品二区三区线观看| 久久天堂av综合合色| 欧美最近摘花xxxx摘花| 免费91在线视频|