亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解golang中Context超時(shí)控制與原理

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

Context

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

Never start a goroutine without knowing how it will stop。

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

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

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

Context標(biāo)準(zhǔn)庫

在Context標(biāo)準(zhǔn)庫中重要的結(jié)構(gòu) context.Context其實(shí)是一個(gè)接口,它提供了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的過期時(shí)間。Deadline第一個(gè)返回值表示Context的過期時(shí)間,第二個(gè)返回值表示是否設(shè)置了過期時(shí)間,如果多次調(diào)用Deadline方法會(huì)返回相同的值。

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

  • 通道關(guān)閉后,Err方法回返回退出的原因。

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

Context是一個(gè)接口,這意味著需要有對應(yīng)的具體實(shí)現(xiàn)。用戶可以自己實(shí)現(xiàn)Context接口,并嚴(yán)格遵守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標(biāo)準(zhǔn)庫中的實(shí)現(xiàn)。
前三個(gè)函數(shù)都用于派生出有退出功能的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函數(shù)回返回一個(gè)子Context和cancel方法。子Context會(huì)在兩種情況下觸發(fā)退出:一種情況是調(diào)用者主動(dòng)調(diào)用了返回的cancel方法;另一種情況是當(dāng)參數(shù)中的父Context退出時(shí),子Context將級聯(lián)退出。
  • WithTimeout函數(shù)指定超時(shí)時(shí)間。當(dāng)超時(shí)發(fā)生后,子Context將退出。因此,子Context的退出有三種時(shí)機(jī),一種是父Context退出;一種是超時(shí)退出;最后一種是主動(dòng)調(diào)用cancel函數(shù)退出。
  • WithDeadline和WithTimeout函數(shù)的處理方法相似,不過它們的參數(shù)指定的是最后到期的時(shí)間。
  • WithValue函數(shù)會(huì)返回帶key-value的子Context。

Context實(shí)踐

eg:

下面的代碼中childCtx是preCtx的子Context,其設(shè)置的超時(shí)時(shí)間為300ms。但是preCtx的超時(shí)時(shí)間為100ms,因此父Context退出后,子Context會(huì)立即退出,實(shí)際的等待時(shí)間只有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退出的時(shí)間差接近100ms:

pre during: 104
child during: 104

當(dāng)我們把preCtx的超時(shí)時(shí)間修改為500ms時(shí):

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

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

child during: 304
pre during: 500

Context底層原理

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

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

要使用context的退出功能,需要調(diào)用WithCancel或WithTimeout,派生出一個(gè)新的結(jié)構(gòu)Context。WithCancel底層對應(yīng)的結(jié)構(gòu)為cancelCtx,WithTimeout底層對應(yīng)的結(jié)構(gòu)為timerCtx,timerCtx包裝了cancelCtx,并存儲(chǔ)了超時(shí)時(shí)間。

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第一個(gè)字段保留了父Context的信息。children字段則保存了當(dāng)前Context派生的子Context的信息,每個(gè)Context都會(huì)有一個(gè)單獨(dú)的done通道。

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

當(dāng)我們使用了標(biāo)準(zhǔn)庫中默認(rèn)的Context實(shí)現(xiàn)時(shí),propagateCancel函數(shù)將子Context加入父協(xié)程的children哈希表中,并開啟一個(gè)定時(shí)器。當(dāng)定時(shí)器到期時(shí),會(huì)調(diào)用cancel方法關(guān)閉通道,級聯(lián)關(guān)閉當(dāng)前Context派生的子Context,并取消與父Context的綁定關(guān)系。這種特性就產(chǎn)生了調(diào)用鏈上連鎖的退出反應(yīng)。

以上就是詳解golang中Context超時(shí)控制與原理的詳細(xì)內(nèi)容,更多關(guān)于golang Context超時(shí)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

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

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

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

    Golang之如何讀取文件內(nèi)容

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

    Go語言中的內(nèi)存布局詳解

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

    Golang實(shí)現(xiàn)IO操作

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

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

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

    Golang實(shí)踐筆錄之讀取yaml配置文件

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

    Go語言七篇入門教程七GC垃圾回收三色標(biāo)記

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

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

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

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

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

    Golang中如何對MySQL進(jìn)行操作詳解

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

最新評論