溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

golang 中 context的作用是什么

發(fā)布時間:2021-07-20 15:12:23 來源:億速云 閱讀:342 作者:Leah 欄目:編程語言

今天就跟大家聊聊有關(guān)golang 中 context的作用是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

 

上下文 context

上下文 context.ContextGo 語言中用來設(shè)置截止日期、同步信號,傳遞請求相關(guān)值的結(jié)構(gòu)體。上下文與 Goroutine 有比較密切的關(guān)系,是 Go 語言中獨特的設(shè)計,在其他編程語言中我們很少見到類似的概念。

context.ContextGo 語言在 1.7 版本中引入標(biāo)準(zhǔn)庫的接口,該接口定義了四個需要實現(xiàn)的方法,其中包括:

  • Deadline — 返回     context.Context 被取消的時間,也就是完成工作的截止日期;
  • Done — 返回一個     Channel,這個     Channel 會在當(dāng)前工作完成或者上下文被取消后關(guān)閉,多次調(diào)用     Done 方法會返回同一個     Channel;
  • Err — 返回     context.Context 結(jié)束的原因,它只會在     Done 方法對應(yīng)的     Channel 關(guān)閉時返回非空的值;如果     context.Context 被取消,會返回     Canceled 錯誤;如果 c     ontext.Context 超時,會返回     DeadlineExceeded 錯誤;
  • Value — 從     context.Context 中獲取鍵對應(yīng)的值,對于同一個上下文來說,多次調(diào)用     Value 并傳入相同的     Key 會返回相同的結(jié)果,該方法可以用來傳遞請求特定的數(shù)據(jù);
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
 

context 包中提供的 context.Backgroundcontext.TODO、context.WithDeadlinecontext.WithValue 函數(shù)會返回實現(xiàn)該接口的私有結(jié)構(gòu)體。

 

信號同步

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)
}
}
Go

   

默認(rèn)上下文

context 包中最常用的方法還是 context.Background、context.TODO,這兩個方法都會返回預(yù)先初始化好的私有變量 backgroundtodo,它們會在同一個 Go 程序中被復(fù)用

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

background 通常用在 main 函數(shù)中,作為所有 context 的根節(jié)點。

todo 通常用在并不知道傳遞什么 context 的情形。例如,調(diào)用一個需要傳遞 context 參數(shù)的函數(shù),你手頭并沒有其他 context 可以傳遞,這時就可以傳遞 todo。這常常發(fā)生在重構(gòu)進行中,給一些函數(shù)添加了一個 Context 參數(shù),但不知道要傳什么,就用 todo “占個位子”,最終要換成其他 context。

 

取消

context.WithCancel 函數(shù)能夠從context.Context 中衍生出一個新的子上下文并返回用于取消該上下文的函數(shù)。一旦我們執(zhí)行返回的取消函數(shù),當(dāng)前上下文以及它的子上下文都會被取消,所有的Goroutine 都會同步收到這一取消信號。

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() { c.cancel(true, Canceled) }
}
 
func propagateCancel(parent Context, child canceler) {
done := parent.Done()
if done == nil {
return // 父上下文不會觸發(fā)取消信號
}
select {
case <-done:
child.cancel(false, parent.Err()) // 父上下文已經(jīng)被取消
return
default:
}

if p, ok := parentCancelCtx(parent); ok {
p.mu.Lock()
if p.err != nil {
child.cancel(false, p.err)
} else {
p.children[child] = struct{}{}
}
p.mu.Unlock()
} else {
go func() {
select {
case <-parent.Done():
child.cancel(false, parent.Err())
case <-child.Done():
}
}()
}
}
 
  1. 當(dāng) parent.Done() == nil,也就是 parent 不會觸發(fā)取消事件時,當(dāng)前函數(shù)會直接返回;
  2. 當(dāng) child 的繼承鏈包含可以取消的上下文時,會判斷 parent 是否已經(jīng)觸發(fā)了取消信號;如果已經(jīng)被取消,child 會立刻被取消;如果沒有被取消,child 會被加入 parent 的 children 列表中,等待 parent 釋放取消信號;
  3. 當(dāng)父上下文是開發(fā)者自定義的類型、實現(xiàn)了 context.Context 接口并在 Done() 方法中返回了非空的管道時;運行一個新的 Goroutine 同時監(jiān)聽 parent.Done() 和 child.Done() 兩個 Channel;在 parent.Done() 關(guān)閉時調(diào)用 child.cancel 取消子上下文;
 

值傳遞

context 包中的 context.WithValue 能從父上下文中創(chuàng)建一個子上下文,傳值的子上下文使用 context.valueCtx 類型

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}
}
 
type valueCtx struct {
Context
key, val interface{}
}

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

看完上述內(nèi)容,你們對golang 中 context的作用是什么有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI