欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解golang中Context超時控制與原理

 更新時間:2024年01月23日 09:28:38   作者:m舊褲子  
Context本身的含義是上下文,我們可以理解為它內部攜帶了超時信息、退出信號,以及其他一些上下文相關的值,本文給大家詳細介紹了golang中Context超時控制與原理,文中有相關的代碼示例供大家參考,需要的朋友可以參考下

Context

在Go語言圈子中流行著一句話:

Never start a goroutine without knowing how it will stop。

翻譯:如果你不知道協(xié)程如何退出,就不要使用它。

在創(chuàng)建協(xié)程時,我們可能還會再創(chuàng)建一些別的子協(xié)程,那么這些協(xié)程的退出就成了問題。在Go1.7之后,Go官方引入了Context來實現(xiàn)協(xié)程的退出。不僅如此,Context還提供了跨協(xié)程、甚至是跨服務的退出管理。

Context本身的含義是上下文,我們可以理解為它內部攜帶了超時信息、退出信號,以及其他一些上下文相關的值(例如攜帶本次請求中上下游的唯一標識trace_id)。由于Context攜帶了上下文信息,父子協(xié)程之間就可以”聯(lián)動“ 了。

Context標準庫

在Context標準庫中重要的結構 context.Context其實是一個接口,它提供了Deadline、Done、Err、Value這4種方法:

type Context interface {
   Deadline() (deadline time.Time, ok bool)
   Done() <-chan struct{}
   Err() error
   Value(key interface{}) interface{}
 }
  • Deadline方法用于返回Context的過期時間。Deadline第一個返回值表示Context的過期時間,第二個返回值表示是否設置了過期時間,如果多次調用Deadline方法會返回相同的值。

  • Done是使用最頻繁的方法,它會返回一個通道。一般的做法是調用者在select中監(jiān)聽該通道的信號,如果該通道關閉則表示服務超時或異常,需要執(zhí)行后續(xù)退出邏輯。多次調用Done方法會返回相同的通道。

  • 通道關閉后,Err方法回返回退出的原因。

  • Value方法返回指定Key對應的value,這是Context攜帶的值。Key必須是可比較的,一般用法Key是一個全局變量,通過context.WithValue將key存儲到Context中,并通過Context.Value方法退出。

Context是一個接口,這意味著需要有對應的具體實現(xiàn)。用戶可以自己實現(xiàn)Context接口,并嚴格遵守Context接口。

func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
    return
}

func (*emptyCtx) Done() <-chan struct{} {
    return nil
}

func (*emptyCtx) Err() error {
    return nil
}

func (*emptyCtx) Value(key interface{}) interface{} {
    return nil
}

因此,要具體使用Context,需要派生出新的Context。我們使用的最多的還是Go標準庫中的實現(xiàn)。
前三個函數都用于派生出有退出功能的Context。

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
  • WithCancel函數回返回一個子Context和cancel方法。子Context會在兩種情況下觸發(fā)退出:一種情況是調用者主動調用了返回的cancel方法;另一種情況是當參數中的父Context退出時,子Context將級聯(lián)退出。
  • WithTimeout函數指定超時時間。當超時發(fā)生后,子Context將退出。因此,子Context的退出有三種時機,一種是父Context退出;一種是超時退出;最后一種是主動調用cancel函數退出。
  • WithDeadline和WithTimeout函數的處理方法相似,不過它們的參數指定的是最后到期的時間。
  • WithValue函數會返回帶key-value的子Context。

Context實踐

eg:

下面的代碼中childCtx是preCtx的子Context,其設置的超時時間為300ms。但是preCtx的超時時間為100ms,因此父Context退出后,子Context會立即退出,實際的等待時間只有100ms。

func main() {
   ctx := context.Background()
   before := time.Now()
   preCtx, _ := context.WithTimeout(ctx, 100*time.Millisecond)
   
   go func() {
   childCtx, _ := context.WithTimeout(preCtx, 300*time.Millisecond)
   select {
    case <-childCtx.Done():
   after := time.Now()
   fmt.Println("child during:", after.Sub(before).Milliseconds())
   }
 }()
 
 select {
    case <-preCtx.Done():
    after := time.Now()
    fmt.Println("pre during:", after.Sub(before).Milliseconds())
 }
 }

這是輸出如下,父Context與子Context退出的時間差接近100ms:

pre during: 104
child during: 104

當我們把preCtx的超時時間修改為500ms時:

preCtx ,_:= context.WithTimeout(ctx,500*time.Millisecond)

從新的輸出中可以看出,子協(xié)程的退出不會影響父協(xié)程的退出。

child during: 304
pre during: 500

Context底層原理

Context在很大程度上利用了通道的一個特性:通道在close時,會通知所有監(jiān)聽它的協(xié)程。

每個派生出的子Context都會創(chuàng)建一個新的退出通道,這樣,只要組織好Context之間的關系,就可以實現(xiàn)繼承鏈上退出信號的傳遞。如圖所示的三個協(xié)程中,關閉通道A會連帶關閉調用鏈上的通道B,通道B會關閉通道C。

要使用context的退出功能,需要調用WithCancel或WithTimeout,派生出一個新的結構Context。WithCancel底層對應的結構為cancelCtx,WithTimeout底層對應的結構為timerCtx,timerCtx包裝了cancelCtx,并存儲了超時時間。

type cancelCtx struct {
	Context

	mu       sync.Mutex            // protects following fields
	done     atomic.Value          // of chan struct{}, created lazily, closed by first cancel call
	children map[canceler]struct{} // set to nil by the first cancel call
	err      error                 // set to non-nil by the first cancel call
	cause    error                 // set to non-nil by the first cancel call
}

type timerCtx struct {
	cancelCtx
	timer *time.Timer // Under cancelCtx.mu.

	deadline time.Time
}

cancelCtx第一個字段保留了父Context的信息。children字段則保存了當前Context派生的子Context的信息,每個Context都會有一個單獨的done通道。

而WithDeadline函數會先判斷父Context設置的超時時間是否比當前Context的超時時間短,如果是,那么子協(xié)程會隨著父Context的退出而退出,沒有必要再設置定時器。

當我們使用了標準庫中默認的Context實現(xiàn)時,propagateCancel函數將子Context加入父協(xié)程的children哈希表中,并開啟一個定時器。當定時器到期時,會調用cancel方法關閉通道,級聯(lián)關閉當前Context派生的子Context,并取消與父Context的綁定關系。這種特性就產生了調用鏈上連鎖的退出反應。

以上就是詳解golang中Context超時控制與原理的詳細內容,更多關于golang Context超時的資料請關注腳本之家其它相關文章!

相關文章

  • Go Java算法之Excel表列名稱示例詳解

    Go Java算法之Excel表列名稱示例詳解

    這篇文章主要為大家介紹了Go Java算法之Excel表列名稱示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Golang之如何讀取文件內容

    Golang之如何讀取文件內容

    這篇文章主要介紹了Golang之如何讀取文件內容問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Go語言中的內存布局詳解

    Go語言中的內存布局詳解

    這篇文章主要給大家介紹了Go語言中的內存布局,那么本文中將嘗試解釋Go如何在內存中構建結構體,以及結構體在字節(jié)和比特位方面是什么樣子。 有需要的朋友們可以參考借鑒,感興趣的朋友們下面來跟著小編一起學習學習吧。
    2016-11-11
  • Golang實現(xiàn)IO操作

    Golang實現(xiàn)IO操作

    本文主要介紹了Golang實現(xiàn)IO操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-05-05
  • 一文帶你了解Go中跟蹤函數調用鏈的實現(xiàn)

    一文帶你了解Go中跟蹤函數調用鏈的實現(xiàn)

    這篇文章主要為大家詳細介紹了go如何實現(xiàn)一個自動注入跟蹤代碼,并輸出有層次感的函數調用鏈跟蹤命令行工具,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-11-11
  • Golang實踐筆錄之讀取yaml配置文件

    Golang實踐筆錄之讀取yaml配置文件

    YAML是YAML?Ain't?a?Markup?Language的縮寫,YAML不是一種標記語言,相比JSON格式的方便,這篇文章主要給大家介紹了關于Golang實踐筆錄之讀取yaml配置文件的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-01-01
  • Go語言七篇入門教程七GC垃圾回收三色標記

    Go語言七篇入門教程七GC垃圾回收三色標記

    這篇文章主要為大家介紹了Go語言教程關于GC垃圾回收三色標記的示例詳解,本篇文章是Go語言七篇入門教程系列文章,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • 深入理解go緩存庫freecache的使用

    深入理解go緩存庫freecache的使用

    go開發(fā)緩存場景一般使用map或者緩存框架,為了線程安全會使用sync.Map或線程安全的緩存框架,本文就詳細的介紹了go緩存庫freecache,感興趣的可以了解一下
    2022-02-02
  • Golang打包配置文件的實現(xiàn)示例

    Golang打包配置文件的實現(xiàn)示例

    本文主要介紹了Golang打包配置文件的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Golang中如何對MySQL進行操作詳解

    Golang中如何對MySQL進行操作詳解

    這篇文章主要給大家介紹了關于在Golang中如何對MySQL進行操作的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者使用Golang具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-03-03

最新評論