一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

關于GO CONTEXT機制實現原則

馬哥Linux運維 ? 來源:cnblogs ? 2023-11-16 16:15 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1 什么是Context

最近在公司分析gRPC源碼,proto文件生成的代碼,接口函數第一個參數統(tǒng)一是ctx context.Context接口,公司不少同事都不了解這樣設計的出發(fā)點是什么,其實我也不了解其背后的原理。今天趁著妮妲臺風妹子正面登陸深圳,全市停工、停課、停業(yè),在家休息找了一些資料研究把玩一把。

Context通常被譯作上下文,它是一個比較抽象的概念。在公司技術討論時也經常會提到上下文。一般理解為程序單元的一個運行狀態(tài)、現場、快照,而翻譯中上下又很好地詮釋了其本質,上下上下則是存在上下層的傳遞,上會把內容傳遞給下。在Go語言中,程序單元也就指的是Goroutine。

每個Goroutine在執(zhí)行之前,都要先知道程序當前的執(zhí)行狀態(tài),通常將這些執(zhí)行狀態(tài)封裝在一個Context變量中,傳遞給要執(zhí)行的Goroutine中。上下文則幾乎已經成為傳遞與請求同生存周期變量的標準方法。在網絡編程下,當接收到一個網絡請求Request,處理Request時,我們可能需要開啟不同的Goroutine來獲取數據與邏輯處理,即一個請求Request,會在多個Goroutine中處理。而這些Goroutine可能需要共享Request的一些信息;同時當Request被取消或者超時的時候,所有從這個Request創(chuàng)建的所有Goroutine也應該被結束。

2 context包

Go的設計者早考慮多個Goroutine共享數據,以及多Goroutine管理機制。Context介紹請參考Go Concurrency Patterns: Context,golang.org/x/net/context包就是這種機制的實現。

context包不僅實現了在程序單元之間共享狀態(tài)變量的方法,同時能通過簡單的方法,使我們在被調用程序單元的外部,通過設置ctx變量值,將過期或撤銷這些信號傳遞給被調用的程序單元。在網絡編程中,若存在A調用B的API, B再調用C的API,若A調用B取消,那也要取消B調用C,通過在A,B,C的API調用之間傳遞Context,以及判斷其狀態(tài),就能解決此問題,這是為什么gRPC的接口中帶上ctx context.Context參數的原因之一。

Go1.7(當前是RC2版本)已將原來的golang.org/x/net/context包挪入了標準庫中,放在$GOROOT/src/context下面。標準庫中net、net/http、os/exec都用到了context。同時為了考慮兼容,在原golang.org/x/net/context包下存在兩個文件,go17.go是調用標準庫的context包,而pre_go17.go則是之前的默認實現,其介紹請參考go程序包源碼解讀。

context包的核心就是Context接口,其定義如下:

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

Deadline會返回一個超時時間,Goroutine獲得了超時時間后,例如可以對某些io操作設定超時時間。

Done方法返回一個信道(channel),當Context被撤銷或過期時,該信道是關閉的,即它是一個表示Context是否已關閉的信號。

當Done信道關閉后,Err方法表明Context被撤的原因。

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

Context接口沒有提供方法來設置其值和過期時間,也沒有提供方法直接將其自身撤銷。也就是說,Context不能改變和撤銷其自身。那么該怎么通過Context傳遞改變后的狀態(tài)呢?

3 context使用

無論是Goroutine,他們的創(chuàng)建和調用關系總是像層層調用進行的,就像人的輩分一樣,而更靠頂部的Goroutine應有辦法主動關閉其下屬的Goroutine的執(zhí)行(不然程序可能就失控了)。為了實現這種關系,Context結構也應該像一棵樹,葉子節(jié)點須總是由根節(jié)點衍生出來的。

要創(chuàng)建Context樹,第一步就是要得到根節(jié)點,context.Background函數的返回值就是根節(jié)點:

func Background() Context

該函數返回空的Context,該Context一般由接收請求的第一個Goroutine創(chuàng)建,是與進入請求對應的Context根節(jié)點,它不能被取消、沒有值、也沒有過期時間。它常常作為處理Request的頂層context存在。

有了根節(jié)點,又該怎么創(chuàng)建其它的子節(jié)點,孫節(jié)點呢?context包為我們提供了多個函數來創(chuàng)建他們:

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 interface{}, val interface{}) Context

函數都接收一個Context類型的參數parent,并返回一個Context類型的值,這樣就層層創(chuàng)建出不同的節(jié)點。子節(jié)點是從復制父節(jié)點得到的,并且根據接收參數設定子節(jié)點的一些狀態(tài)值,接著就可以將子節(jié)點傳遞給下層的Goroutine了。

再回到之前的問題:該怎么通過Context傳遞改變后的狀態(tài)呢?使用Context的Goroutine無法取消某個操作,其實這也是符合常理的,因為這些Goroutine是被某個父Goroutine創(chuàng)建的,而理應只有父Goroutine可以取消操作。在父Goroutine中可以通過WithCancel方法獲得一個cancel方法,從而獲得cancel的權利。

第一個WithCancel函數,它是將父節(jié)點復制到子節(jié)點,并且還返回一個額外的CancelFunc函數類型變量,該函數類型的定義為:

type CancelFunc func()

調用CancelFunc對象將撤銷對應的Context對象,這就是主動撤銷Context的方法。在父節(jié)點的Context所對應的環(huán)境中,通過WithCancel函數不僅可創(chuàng)建子節(jié)點的Context,同時也獲得了該節(jié)點Context的控制權,一旦執(zhí)行該函數,則該節(jié)點Context就結束了,則子節(jié)點需要類似如下代碼來判斷是否已結束,并退出該Goroutine:

select {
    case <-cxt.Done():
        // do some clean...
}

WithDeadline函數的作用也差不多,它返回的Context類型值同樣是parent的副本,但其過期時間由deadline和parent的過期時間共同決定。當parent的過期時間早于傳入的deadline時間時,返回的過期時間應與parent相同。父節(jié)點過期時,其所有的子孫節(jié)點必須同時關閉;反之,返回的父節(jié)點的過期時間則為deadline。

WithTimeout函數與WithDeadline類似,只不過它傳入的是從現在開始Context剩余的生命時長。他們都同樣也都返回了所創(chuàng)建的子Context的控制權,一個CancelFunc類型的函數變量。

當頂層的Request請求函數結束后,我們就可以cancel掉某個context,從而層層Goroutine根據判斷cxt.Done()來結束。

WithValue函數,它返回parent的一個副本,調用該副本的Value(key)方法將得到val。這樣我們不光將根節(jié)點原有的值保留了,還在子孫節(jié)點中加入了新的值,注意若存在Key相同,則會被覆蓋。

3.1 小結

context包通過構建樹型關系的Context,來達到上一層Goroutine能對傳遞給下一層Goroutine的控制。對于處理一個Request請求操作,需要采用context來層層控制Goroutine,以及傳遞一些變量來共享。

Context對象的生存周期一般僅為一個請求的處理周期。即針對一個請求創(chuàng)建一個Context變量(它為Context樹結構的根);在請求處理結束后,撤銷此ctx變量,釋放資源。

每次創(chuàng)建一個Goroutine,要么將原有的Context傳遞給Goroutine,要么創(chuàng)建一個子Context并傳遞給Goroutine。

Context能靈活地存儲不同類型、不同數目的值,并且使多個Goroutine安全地讀寫其中的值。

當通過父Context對象創(chuàng)建子Context對象時,可同時獲得子Context的一個撤銷函數,這樣父Context對象的創(chuàng)建環(huán)境就獲得了對子Context將要被傳遞到的Goroutine的撤銷權。

4 使用原則

Programs that use Contexts should follow these rules to keep interfaces consistent across packages and enable static analysis tools to check context propagation:
使用Context的程序包需要遵循如下的原則來滿足接口的一致性以及便于靜態(tài)分析。

在子Context被傳遞到的goroutine中,應該對該子Context的Done信道(channel)進行監(jiān)控,一旦該信道被關閉(即上層運行環(huán)境撤銷了本goroutine的執(zhí)行),應主動終止對當前請求信息的處理,釋放資源并返回。

Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctx;不要把Context存在一個結構體當中,顯式地傳入函數。Context變量需要作為第一個參數使用,一般命名為ctx;

Do not pass a nil Context, even if a function permits it. Pass context.TODO if you are unsure about which Context to use;即使方法允許,也不要傳入一個nil的Context,如果你不確定你要用什么Context的時候傳一個context.TODO;

Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions;使用context的Value相關方法只應該用于在程序和接口中傳遞的和請求相關的元數據,不要用它來傳遞一些可選的參數;

The same Context may be passed to functions running in different goroutines; Contexts are safe for simultaneous use by multiple goroutines;同樣的Context可以用來傳遞到不同的goroutine中,Context在多個goroutine中是安全的;

編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • API
    API
    +關注

    關注

    2

    文章

    1620

    瀏覽量

    64048
  • 函數
    +關注

    關注

    3

    文章

    4381

    瀏覽量

    64890
  • 網絡編程
    +關注

    關注

    0

    文章

    72

    瀏覽量

    10630
  • go語言
    +關注

    關注

    1

    文章

    159

    瀏覽量

    9373

原文標題:理解GO CONTEXT機制

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    鴻蒙開發(fā)接口Ability框架:【 (Context模塊)】

    Context模塊提供了ability或application的上下文的能力,包括允許訪問特定于應用程序的資源、請求和驗證權限等。
    的頭像 發(fā)表于 05-13 16:04 ?1144次閱讀
    鴻蒙開發(fā)接口Ability框架:【 (<b class='flag-5'>Context</b>模塊)】

    鴻蒙開發(fā)接口Ability框架:【Context

    Context模塊提供開發(fā)者運行代碼的上下文環(huán)境的能力,包括查詢和設置應用信息、ResourceManager等信息。
    的頭像 發(fā)表于 05-21 17:33 ?1272次閱讀
    鴻蒙開發(fā)接口Ability框架:【<b class='flag-5'>Context</b>】

    Context接口切換介紹

    Context接口切換 FA接口Stage模型接口對應d.ts文件Stage對應接口或字段getOrCreateLocalDir(callback:AsyncCallback):void
    發(fā)表于 06-06 06:12

    鏈接CAN RX郵箱的FIFO機制怎么使用?

    = 31578但我不知道如何應用這一原則,因為我不知道如何訪問讀寫指針。我要計劃這個指針機制(讀寫指針)我自己?有沒有關于如何正確處理的例子?提前感謝!
    發(fā)表于 08-28 10:41

    關于IAR軟件的Go to Definition of功能問題解決

    再用IAR軟件時 總是遇到“go to difination”的問題 在網上搜了一篇關于解決的辦法,挺實用的
    發(fā)表于 07-22 16:08 ?2次下載

    關于高阻態(tài)和OOC(out of context)綜合方式

    Xilinx Vivado工具支持僅將系統(tǒng)設計的一部分進行綜合,即OOC(out of context)綜合方式。OOC綜合方式的流程就是將設計的某個模塊單獨完成綜合操作,這會帶來如下可能性
    發(fā)表于 03-21 09:50 ?6093次閱讀

    dubbo-go 中的 TPS Limit 設計與實現

    則是 Dubbo 的 Go 語言實現。 最近在 dubbo-go 的 todo list 上發(fā)現,它還沒有實現 TPS Limit 的模塊,于是就抽空
    發(fā)表于 03-17 15:27 ?758次閱讀

    golang并發(fā)機制和其他語言在實現上有什么不同

    golang 并發(fā)機制和其他語言在實現上有什么不同?為什么能做到高效快速?本文做了詳細介紹。 由于對普通語法的介紹網上資源極多,Go 官方的上手指南 A Tour of Go: htt
    的頭像 發(fā)表于 07-29 16:35 ?1648次閱讀
    golang并發(fā)<b class='flag-5'>機制</b>和其他語言在<b class='flag-5'>實現</b>上有什么不同

    Go語言的默認機制

    不過麻煩的事情來了。我們寫一個程序,就是想在別人的電腦上運行的。然而,Go語言的默認機制,會泄漏我們的一些信息,雖然不多,但也有點尷尬。本文結合網上的一些常用方法,總結出一套通用的簡單易行的保護措施。
    的頭像 發(fā)表于 03-21 11:50 ?1435次閱讀

    Go并發(fā)模型的實現原理

    Go語言是為并發(fā)而生的語言,Go語言是為數不多的在語言層面實現并發(fā)的語言;也正是Go語言的并發(fā)特性,吸引了全球無數的開發(fā)者。
    的頭像 發(fā)表于 04-15 08:49 ?1634次閱讀

    朋也社區(qū)Go版本Go實現的社區(qū)系統(tǒng)

    ./oschina_soft/pybbs-go.zip
    發(fā)表于 06-10 14:32 ?0次下載
    朋也社區(qū)<b class='flag-5'>Go</b>版本<b class='flag-5'>Go</b><b class='flag-5'>實現</b>的社區(qū)系統(tǒng)

    In-context learning介紹

    隨著大規(guī)模預訓練語言模型(LLM)能力的不斷提升,in-context learning(ICL)逐漸成為自然語言處理領域一個新的范式。
    的頭像 發(fā)表于 04-21 10:02 ?2101次閱讀

    鴻蒙開發(fā)接口Ability框架:【Context

    Context模塊提供開發(fā)者運行代碼的上下文環(huán)境的能力,包括查詢和設置應用信息、ResourceManager等信息。
    的頭像 發(fā)表于 05-15 15:29 ?882次閱讀
    鴻蒙開發(fā)接口Ability框架:【<b class='flag-5'>Context</b>】

    鴻蒙開發(fā)組件:FA模型的Context

    FA模型下只有一個Context。Context中的所有功能都是通過方法來提供的,它提供了一些featureAbility中不存在的方法,相當于featureAbility的一個擴展和補全。
    的頭像 發(fā)表于 06-21 09:43 ?596次閱讀
    鴻蒙開發(fā)組件:FA模型的<b class='flag-5'>Context</b>

    從 Java 到 Go:面向對象的巨人與云原生的輕騎兵

    不同,Go 通過編譯為 單一靜態(tài)二進制文件實現快速啟動和低內存開銷 , 以25個關鍵字強制代碼簡潔性 , 用接口組合替代類繼承 , 以顯式返回error取代異常機制 和 輕量級并發(fā)模型
    的頭像 發(fā)表于 04-25 11:13 ?234次閱讀