go context

context 很重要,總體作用就是 設(shè)置程序執(zhí)行的

  • deadline 設(shè)置程序的截止日期
  • status sync 同步信號(hào)
  • submit value 設(shè)置共享變量

當(dāng)上層 goroutine 需要通知 他下級(jí) goroutine 及時(shí)終止程序,釋放資源的時(shí)候,常用 context

簡(jiǎn)單來說,這三個(gè)功能貌似都可以使用 channel 實(shí)現(xiàn),比如所有 gorountine 實(shí)現(xiàn)關(guān)閉,只要判斷 channel close 了,就把所有函數(shù) return ,釋放資源。傳遞值也可以 通過 channel, 但是 記住 channel 的東西拿到一次就清除了。而context value 卻可以多次取值。還有很多區(qū)別,下面就詳細(xì)說一下 context 都有那些用處。

參考 [go 設(shè)計(jì)和實(shí)現(xiàn) 上下文 ](Context https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-context/)

context.Context 里面有什么東西

type Context interface {
    Deadline() (deadline time.Time, ok bool)     // 設(shè)置截至日期
    Done() <-chan struct{}    // 當(dāng)前上下文 被取消時(shí)候,關(guān)閉, 
    Err() error     // 上下文結(jié)束的時(shí)候,返回 Canceled / DeadlineExceeded 錯(cuò)誤
    Value(key interface{}) interface{}  // 獲取鍵值對(duì)
}

他就是一個(gè)接口,很簡(jiǎn)單吧,這個(gè)接口只是定義了最基本的 context 的東西,很多context 都是實(shí)現(xiàn)了這個(gè)接口,然后擴(kuò)展了很多功能。

context.Context 里面的幾個(gè)函數(shù)

context.emptyCtx

這個(gè)可以看出 她是 context 包的私有屬性, 他只是為了 提供一個(gè) 實(shí)現(xiàn)了 context.Context 接口的 空 上下文,因?yàn)樗鼘?shí)現(xiàn)的函數(shù),沒有具體的功能,只是為了給別人繼承用的

type emptyCtx int

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.Background , context.TODO

var (
    background = new(emptyCtx)
    todo       = new(emptyCtx)
)


func Background() Context {
    return background
}

func TODO() Context {
    return todo
}

其實(shí) Background 和 TODO 實(shí)質(zhì)試一樣的,只是 變量名有種表面的含義
Background 代表 默認(rèn)上下文, 而 TODO 代表 可能還不確定,怎么用。只是給開發(fā)人員看起來知道大概 context 大概用來干嘛的
(ps context 是可以被嵌套的,一級(jí)一級(jí) 包裝, 添加更多的功能,就像繼承一樣)

創(chuàng)建一個(gè)可以被取消的 context

context.WithCancel

ctx := context.Background()
ctx,  cancel  := context.WithCancel(ctx)

// 在 其他 函數(shù)使用 ctx
cancel( )  // 關(guān)閉所有 goroutine  相關(guān)

// 所有使用  ctx 的 goroutine  ctx.Done()  會(huì)有值, 那就表示要結(jié)束了,我們可以用 for  select 結(jié)構(gòu)   <- ctx.Done()  這樣判斷是不是需要結(jié)束這個(gè) gorountine。

for {
select {
    case <- ctx.Done():
        child.cancel(false, parent.Err()) // 父上下文已經(jīng)被取消
        return
        default:
                // todo
}

創(chuàng)建一個(gè)可以被 定時(shí) 關(guān)閉的 context

context.WithDeadline // 第二個(gè)參數(shù)是時(shí)間對(duì)象

func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)

context.WithTimeout // 第二個(gè)參數(shù)是時(shí)間間隔

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
    return WithDeadline(parent, time.Now().Add(timeout))
}
ctx, cancel := context.WithDeadline( context.Background(),  time.Now().Add(3 * time.Second)  )   
// 三秒之后自動(dòng)調(diào)用  cancel 函數(shù), 當(dāng)然你也可以手動(dòng)提前執(zhí)行 cancel
// 其實(shí) WithDeadline 內(nèi)部是 調(diào)用 time.AfterFunc  延遲調(diào)用的 cancel

創(chuàng)建一個(gè) 可以傳值的 context

context.WithValue 部分代碼

type valueCtx struct {
    Context
    key, val interface{}
}


func WithValue(parent Context, key, val interface{}) Context {
    if key == nil {
        panic("nil key")
    }
    if !reflectlite.TypeOf(key).Comparable() {
        panic("key is not comparable")
    }
    return &valueCtx{parent, key, val}
}


func (c *valueCtx) Value(key interface{}) interface{} {
    if c.key == key {
        return c.val
    }
    return c.Context.Value(key)
}

繼承一個(gè)父 context 和一個(gè) key value 值,就是簡(jiǎn)單的 設(shè)置 key value 的值, 取值 用 ctx.Value(key) 當(dāng)前 context 沒有 key 就去 上層 去找。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 1 什么是Context 最近在公司分析gRPC源碼,proto文件生成的代碼,接口函數(shù)第一個(gè)參數(shù)統(tǒng)一是ctx c...
    淘小鋪刀仔閱讀 467評(píng)論 0 1
  • 控制并發(fā)有兩種經(jīng)典的方式:WaitGroup和Context WaitGroup:控制多個(gè)Goroutine同時(shí)完...
    JunChow520閱讀 770評(píng)論 0 2
  • https://draveness.me/golang/[https://draveness.me/golang/...
    shuff1e閱讀 683評(píng)論 0 0
  • WHY 每一個(gè)長(zhǎng)請(qǐng)求都應(yīng)該有個(gè)超時(shí)限制需要在調(diào)用中傳遞這個(gè)超時(shí)比如開始處理請(qǐng)求的時(shí)候我們說是 3 秒鐘超時(shí)那么在函...
    林桉閱讀 501評(píng)論 0 0
  • 使用Go作為服務(wù)端開發(fā)時(shí),每個(gè)請(qǐng)求過來都會(huì)分配一個(gè)goroutine來處理,請(qǐng)求處理過程中,可能還會(huì)創(chuàng)建額外的go...
    光華路程序猿閱讀 409評(píng)論 0 0

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