深入Golang之context的用法詳解

2022-09-24 18:21:10 字數 2645 閱讀 4149

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

原始碼分析

首先我們來看一下context裡面核心的幾個資料結構:

context inte***ce

type context inte***ce

生成context的主要方法

withcancel

func withcancel(parent context) (ctx context, cancel cancelfunc)

}返回乙個cancelctx示例,並返回乙個函式,可以在外層直接呼叫cancelctx.cancel()來取消context。

withdeadline

func withdeadline(parent context, deadline time.time) (context, cancelfunc)

c := &timerctx

propagatecancel(parent, c)

d := time.until(deadline)

if d <= 0

} c.mu.lock()

defer c.mu.unlock()

if c.err == nil )

} return c, func()

}返回乙個timerctx示例,設定具體的deadline時間,到達 deadline的時候,後代goroutine退出。

withtimeout

func withtimeout(parent context, timeout time.duration) (context, cancelfunc)

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

withvalue

func withvalue(parent context, key, val inte***ce{}) context

if !reflect.typeof(key).comparable()

return &valuectx

}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 longrunningcalculation(timecost int)chan string{

result:=make(chan string)

go func (){

time.sleep(time.second*(time.duration(timecost)))

result

這裡用乙個timerctx來控制乙個函式的執行時間,如果超過了這個時間,就會被迫中斷,這樣就可以控制一些時間比較長的操作,例如io,rpc呼叫等等。

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

總結context包通過構建樹型關係的context,來達到上一層goroutine能對傳遞給下一層goroutine的控制。可以傳遞一些變數來共享,可以控制超時,還可以控制多個goroutine的退出。

據說在google,要求golang程式設計師把context作為第乙個引數傳遞給入口請求和出口請求鏈路上的每乙個函式。這樣一方面保證了多個團隊開發的golang專案能夠良好地協作,另一方面它是一種簡單的超時和取消機制,保證了臨界區資料在不同的golang專案中順利傳遞。

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

本文標題: 深入golang之context的用法詳解

本文位址: /jiaoben/golang/223470.html

Android開發之全域性獲取Context的技巧

第一行 android 高階篇 這本書對於入門來說確實很棒,很簡單明瞭的介紹了android開發中涉及到的方方面面,對我的幫助很大,同時記錄一些該書中一些對我以後開發有用的東西,以方便使用。1 public23 private static context context 45 override 6...

Golang 檔案操作的深入研究

一般來說常用的有四種 使用file自帶的read方法 使用bufio庫的read方法 使用io ioutil庫的readall 使用io ioutil庫的readfile 先說結論 當每次讀取塊的大小小於4kb,建議使用bufio.newreader f 大於4kb用bufio.newreaders...

Golang之繼承模擬

web的controller,希望建立乙個基類,然後在子類的controller中定義action方法,基類有乙個run函式能根據字串自動找到子類的action方法。如何解決呢?用繼承 首先這個需求是很普遍的,由於腦中有繼承概念,所以想當然地以為這個很容易實現 1 2 3 4 5 6 7 8 9 1...