Go Context介紹

context包是Go 語言中用來設置截止日期、同步信號,傳遞請求相關值的結構體,是開發(fā)常用的并發(fā)控制技術。
WaitGroup的不同在于context可以控制多級的goroutine。

1. 接口定義

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

    Err() error

    Value(key interface{}) interface{}
}

Deadline(): 工作的截止時間,沒有設置deadlineok==false。
Done(): 需要在select-case語句中使用(case <-context.Done(): )。當context被關閉后,Done()返回一個被關閉的通道(關閉的通道依然是可以讀的,所以goroutine可以收到關閉請求);當context還未關閉時,Done()返回nil。
Err(): 描述context關閉的原因,其原因由context實現(xiàn)控制。例如:因deadline關閉:context deadline exceeded;因主動關閉:context canceled。沒有關閉時,返回nil。
Value(): 特別的用于一種context:不用于控制呈樹狀分布的goroutine,而是用于在樹狀分布的goroutine之間傳遞信息。Value()方法根據(jù)key值查詢map中的Value。

2. 使用

一個案例來展示context的使用,它做了2件事:1. 創(chuàng)建過期時間為1s的上下文。 2. 將context傳入handle函數(shù)中,函數(shù)使用500ms的時間處理請求。

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()

    go handle(ctx, 500*time.Millisecond)
    select {
    case <-ctx.Done():
        fmt.Println("main", ctx.Err())
    }
}

func handle(ctx context.Context, duration time.Duration) {
    select {
    case <-ctx.Done():
        fmt.Println("handle", ctx.Err())
    case <-time.After(duration):
        fmt.Println("process request with", duration)
    }
}

output:

process request with 500ms
main context deadline exceeded

分析: context過期時間為1s,處理時間為0.5秒(select中的過期時間),函數(shù)有足夠的時間完成處理,也就是<-time.After(duration):會在<-ctx.Done()之前完成,故輸出process request with 500ms。再過0.5s,<-ctx.Done()完成,這時候輸出main context deadline exceeded。

倘若,代碼中的``改為400*time.Millisecond,會輸出什么呢?
A:

main context deadline exceeded

B:

main context deadline exceeded
handle context deadline exceeded

C:

process request with 500ms
main context deadline exceeded

D:

process request with 500ms

E:

handle context deadline exceeded
main context deadline exceeded

答案是:A、B、E
可能出現(xiàn)這3種,而不是1種的原因是和調(diào)度器有關。


context的一些方法

  • 默認上下文: 以下兩個方法都會返回預先初始化好的私有變量 backgroundtodo,它們會在同一個 Go 程序中被復用。這兩個私有變量都是通過 new(emptyCtx) 語句初始化的,它們是指向私有結構體 context.emptyCtx的指針,這是最簡單、最常用的上下文類型。
    • context.Background(): 是上下文的默認值,所有其他的上下文都應該從它衍生出來。
    • context.TODO(): 應該僅在不確定應該使用哪種上下文時使用。
  • 取消信號:前兩個創(chuàng)建的是context.WithCancel,最后一個創(chuàng)建的是context.timerCtx。
    • context.WithCancel(): 由context.Context()衍生出的特殊的子上下文。一旦它的返回函數(shù)被執(zhí)行,其所有子context將都會被返回。
    • context.WithDeadline(): 在某個時間點進行返回。
    • context.WithTimeout(): 某個時間段過后進行返回。
  • 傳值方法
    • context.WithValue(): 從父上下文中創(chuàng)建一個子上下文,傳值的子上下文使用 context.valueCtx。
      需要注意的是這個方法是遞歸的根據(jù)Key來獲取Value的。
func (c *valueCtx) Value(key interface{}) interface{} {
    if c.key == key {
        return c.val
    }
    return c.Context.Value(key)
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Go context 在RPC或者Web服務中,當Server端接受一個request的時候,都會開啟一個額外的g...
    qingshuiting閱讀 8,782評論 0 2
  • Go標準庫Context 在 Go http包的Server中,每一個請求在都有一個對應的 goroutine 去...
    吳佳浩閱讀 496評論 0 2
  • Context 通常被譯作上下文,一般理解為程序單元的一個運行狀態(tài)、現(xiàn)場、快照,而翻譯中上下文又很好地詮釋了它的本...
    Asphalt7閱讀 660評論 0 0
  • 控制并發(fā)有兩種經(jīng)典的方式:WaitGroup和Context WaitGroup:控制多個Goroutine同時完...
    JunChow520閱讀 773評論 0 2
  • 1 什么是Context 最近在公司分析gRPC源碼,proto文件生成的代碼,接口函數(shù)第一個參數(shù)統(tǒng)一是ctx c...
    淘小鋪刀仔閱讀 468評論 0 1

友情鏈接更多精彩內(nèi)容