最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

Context

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

Never start a goroutine without knowing how it will stop。

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

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

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

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

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

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

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

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

Context是一個接口,這意味著需要有對應(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)。
前三個函數(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ù)回返回一個子Context和cancel方法。子Context會在兩種情況下觸發(fā)退出:一種情況是調(diào)用者主動調(diào)用了返回的cancel方法;另一種情況是當(dāng)參數(shù)中的父Context退出時,子Context將級聯(lián)退出。
  • WithTimeout函數(shù)指定超時時間。當(dāng)超時發(fā)生后,子Context將退出。因此,子Context的退出有三種時機(jī),一種是父Context退出;一種是超時退出;最后一種是主動調(diào)用cancel函數(shù)退出。
  • WithDeadline和WithTimeout函數(shù)的處理方法相似,不過它們的參數(shù)指定的是最后到期的時間。
  • WithValue函數(shù)會返回帶key-value的子Context。

Context實(shí)踐

eg:

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

pre during: 104
child during: 104

當(dāng)我們把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之間的關(guān)系,就可以實(shí)現(xiàn)繼承鏈上退出信號的傳遞。如圖所示的三個協(xié)程中,關(guān)閉通道A會連帶關(guān)閉調(diào)用鏈上的通道B,通道B會關(guān)閉通道C。

要使用context的退出功能,需要調(diào)用WithCancel或WithTimeout,派生出一個新的結(jié)構(gòu)Context。WithCancel底層對應(yīng)的結(jié)構(gòu)為cancelCtx,WithTimeout底層對應(yīng)的結(jié)構(gòu)為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字段則保存了當(dāng)前Context派生的子Context的信息,每個Context都會有一個單獨(dú)的done通道。

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

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

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

相關(guān)文章

  • Go語言中序列化與反序列化示例詳解

    Go語言中序列化與反序列化示例詳解

    我們的數(shù)據(jù)對象要在網(wǎng)絡(luò)中傳輸或保存到文件,就需要對其編碼和解碼動作,Go語言當(dāng)然也支持所有這些編碼格式,下面這篇文章主要給大家介紹了關(guān)于Go語言中序列化與反序列化的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Golang時間處理中容易踩的坑分析解決

    Golang時間處理中容易踩的坑分析解決

    這篇文章主要為大家介紹了Golang時間處理中容易踩的坑分析解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Golang實(shí)現(xiàn)按比例切分流量的示例詳解

    Golang實(shí)現(xiàn)按比例切分流量的示例詳解

    我們在進(jìn)行灰度發(fā)布時,往往需要轉(zhuǎn)發(fā)一部分流量到新上線的服務(wù)上,進(jìn)行小規(guī)模的驗(yàn)證,隨著功能的不斷完善,我們也會逐漸增加轉(zhuǎn)發(fā)的流量,這就需要按比例去切分流量,那么如何實(shí)現(xiàn)流量切分呢,接下來小編就給大家詳細(xì)的介紹一下實(shí)現(xiàn)方法,需要的朋友可以參考下
    2023-09-09
  • 一文了解Go 并發(fā)與并行

    一文了解Go 并發(fā)與并行

    并發(fā)性和并行性是是兩個既有聯(lián)系又有所區(qū)別的概念,本文主要介紹了Go并發(fā)與并行,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05
  • Golang實(shí)現(xiàn)優(yōu)雅的將struct轉(zhuǎn)換為map

    Golang實(shí)現(xiàn)優(yōu)雅的將struct轉(zhuǎn)換為map

    在項目實(shí)踐中,有時候我們需要將struct結(jié)構(gòu)體轉(zhuǎn)為map映射表,然后基于map做數(shù)據(jù)裁剪或操作。那么下面我來介紹下常用的兩種轉(zhuǎn)換方式,希望對大家有所幫助
    2023-01-01
  • Golang實(shí)現(xiàn)常見排序算法的示例代碼

    Golang實(shí)現(xiàn)常見排序算法的示例代碼

    現(xiàn)在的面試真的是越來越卷了,算法已經(jīng)成為了面試過程中必不可少的一個環(huán)節(jié),你如果想進(jìn)稍微好一點(diǎn)的公司,算法是必不可少的一個環(huán)節(jié)。本文為大家準(zhǔn)備了Golang實(shí)現(xiàn)常見排序算法的示例代碼,需要的可以參考一下
    2022-05-05
  • 使用Go語言實(shí)現(xiàn)發(fā)送微信群消息

    使用Go語言實(shí)現(xiàn)發(fā)送微信群消息

    這篇文章主要為大家詳細(xì)介紹了如何使用Go語言實(shí)現(xiàn)發(fā)送微信群消息,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • Go語言掃描目錄并獲取相關(guān)信息的方法

    Go語言掃描目錄并獲取相關(guān)信息的方法

    這篇文章主要介紹了Go語言掃描目錄并獲取相關(guān)信息的方法,實(shí)例分析了Go語言操作目錄及文件的技巧,需要的朋友可以參考下
    2015-03-03
  • go語言奇偶轉(zhuǎn)置排序算法實(shí)現(xiàn)方法(附帶源碼)

    go語言奇偶轉(zhuǎn)置排序算法實(shí)現(xiàn)方法(附帶源碼)

    這篇文章主要介紹了go語言奇偶轉(zhuǎn)置排序算法實(shí)現(xiàn)方法的相關(guān)資料,這種算法是一種專門為并行計算環(huán)境設(shè)計的排序算法,它通過交替執(zhí)行奇數(shù)索引和偶數(shù)索引的比較來排序,需要的朋友可以參考下
    2026-02-02
  • Go 加密解密算法小結(jié)

    Go 加密解密算法小結(jié)

    加密解密在實(shí)際開發(fā)中應(yīng)用比較廣泛,常見的加解密分為三種,本文就詳細(xì)的介紹一下Go 加密解密算法,具有一定的參考價值,感興趣的可以了解一下
    2022-01-01

最新評論

阿拉尔市| 都安| 乐陵市| 札达县| 阿图什市| 通海县| 遂溪县| 炎陵县| 新巴尔虎右旗| 蒙自县| 东源县| 桐庐县| 苗栗县| 澄迈县| 西乌珠穆沁旗| 文山县| 静乐县| 襄樊市| 景泰县| 泽普县| 平邑县| 夏河县| 苏尼特左旗| 思茅市| 疏勒县| 博野县| 芒康县| 霍州市| 沽源县| 静安区| 丽江市| 桓仁| 东辽县| 苍山县| 莆田市| 安福县| 轮台县| 工布江达县| 乌苏市| 昌都县| 敦煌市|