您好,登錄后才能下訂單哦!
這篇文章主要介紹了Golang上下文Context的常見應(yīng)用場(chǎng)景是什么的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇Golang上下文Context的常見應(yīng)用場(chǎng)景是什么文章都會(huì)有所收獲,下面我們一起來看看吧。
// A Context carries a deadline, a cancellation signal, and other values across // API boundaries. // Context包含一個(gè)截止日期、一個(gè)取消信號(hào)和跨越API邊界的其他值。 // Context's methods may be called by multiple goroutines simultaneously. // Context的方法可以被多個(gè)goroutine同時(shí)調(diào)用。 type Context interface { // Deadline returns the time when work done on behalf of this context // should be canceled. Deadline returns ok==false when no deadline is // set. Successive calls to Deadline return the same results. // Deadline返回在此context下做完工作應(yīng)該取消的時(shí)間。當(dāng)沒有設(shè)置截止日 // 期時(shí),Deadline返回ok==false。連續(xù)調(diào)用Deadline返回相同的結(jié)果。 Deadline() (deadline time.Time, ok bool) // Done返回一個(gè)通道,當(dāng)在該上下文所做的工作應(yīng)該取消時(shí),該通道關(guān)閉。如果這 // 個(gè)上下文永遠(yuǎn)不能取消,Done可能返回nil。對(duì)Done的連續(xù)調(diào)用返回相同的值。 // Done通道的關(guān)閉可以在cancel函數(shù)返回之后異步發(fā)生 // WithCancel安排Done在cancel被調(diào)用時(shí)關(guān)閉;WithDeadline安排Done在截止 // 日期到期時(shí)關(guān)閉;WithTimeout設(shè)置Done在超時(shí)后關(guān)閉。 // Done提供給select語句使用: // // Stream generates values with DoSomething and sends them to out // // until DoSomething returns an error or ctx.Done is closed. // func Stream(ctx context.Context, out chan<- Value) error { // for { // v, err := DoSomething(ctx) // if err != nil { // return err // } // select { // case <-ctx.Done(): // return ctx.Err() // case out <- v: // } // } // } // // See https://blog.golang.org/pipelines for more examples of how to use // a Done channel for cancellation. Done() <-chan struct{} // If Done is not yet closed, Err returns nil. // If Done is closed, Err returns a non-nil error explaining why: // Canceled if the context was canceled // or DeadlineExceeded if the context's deadline passed. // After Err returns a non-nil error, successive calls to Err return the same error. Err() error // Value返回與上下文相關(guān)的key的值,如果沒有與key相關(guān)的值則返回nil。連 // 續(xù)調(diào)用具有相同鍵的Value返回相同的結(jié)果。 // 僅對(duì)傳輸?shù)竭M(jìn)程和API邊界的請(qǐng)求范圍內(nèi)的數(shù)據(jù)使用上下文值,而不是將可選參 // 數(shù)傳遞給函數(shù)。 // key 標(biāo)識(shí)上下文中的特定值。希望在Context中存儲(chǔ)值的函數(shù)通常在全局變量 // 中分配一個(gè)鍵,可以使用該鍵作為context.WithValue和 // Context.Value的參數(shù)。 key 可以是支持相等的任何類型;包應(yīng)該將key 定義 // 為未導(dǎo)出的類型,以避免沖突。 // 定義Context 鍵的包應(yīng)該為使用該鍵存儲(chǔ)的值提供類型安全的訪問器: // // Package user defines a User type that's stored in Contexts. // package user // // import "context" // // // User is the type of value stored in the Contexts. // type User struct {...} // // // key is an unexported type for keys defined in this package. // // This prevents collisions with keys defined in other packages. // type key int // // // userKey is the key for user.User values in Contexts. It is // // unexported; clients use user.NewContext and user.FromContext // // instead of using this key directly. // var userKey key // // // NewContext returns a new Context that carries value u. // func NewContext(ctx context.Context, u *User) context.Context { // return context.WithValue(ctx, userKey, u) // } // // // FromContext returns the User value stored in ctx, if any. // func FromContext(ctx context.Context) (*User, bool) { // u, ok := ctx.Value(userKey).(*User) // return u, ok // } Value(key any) any }
// emptyCtx永遠(yuǎn)不會(huì)取消,沒有值,也沒有截止日期。它不是struct{},因?yàn)檫@ // 種類型的變量必須有不同的地址。 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 any) any { return nil } func (e *emptyCtx) String() string { switch e { case background: return "context.Background" case todo: return "context.TODO" } return "unknown empty Context" }
// cancelCtx可以被取消。當(dāng)取消時(shí),它還取消實(shí)現(xiàn)canceler的所有子對(duì)象。 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 }
// A canceler is a context type that can be canceled directly. The // implementations are *cancelCtx and *timerCtx. type canceler interface { cancel(removeFromParent bool, err, cause error) Done() <-chan struct{} }
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to // implement Done and Err. It implements cancel by stopping its timer then // delegating to cancelCtx.cancel. type timerCtx struct { *cancelCtx timer *time.Timer // Under cancelCtx.mu. deadline time.Time } func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true } func (c *timerCtx) String() string { return contextName(c.cancelCtx.Context) + ".WithDeadline(" + c.deadline.String() + " [" + time.Until(c.deadline).String() + "])" } func (c *timerCtx) cancel(removeFromParent bool, err, cause error) { c.cancelCtx.cancel(false, err, cause) if removeFromParent { // Remove this timerCtx from its parent cancelCtx's children. removeChild(c.cancelCtx.Context, c) } c.mu.Lock() if c.timer != nil { c.timer.Stop() c.timer = nil } c.mu.Unlock() }
// A valueCtx carries a key-value pair. It implements Value for that key and // delegates all other calls to the embedded Context. type valueCtx struct { Context key, val any } func (c *valueCtx) String() string { return contextName(c.Context) + ".WithValue(type " + reflectlite.TypeOf(c.key).String() + ", val " + stringify(c.val) + ")" } func (c *valueCtx) Value(key any) any { if c.key == key { return c.val } return value(c.Context, key) }
context
包中最常用的方法還是 context.Background
、context.TODO
,這兩個(gè)方法都會(huì)返回預(yù)先初始化好的私有變量 background
和 todo
,它們會(huì)在同一個(gè) Go 程序中被復(fù)用:
// Background返回一個(gè)非nil的空Context。它永遠(yuǎn)不會(huì)被取消,沒有values,也沒 // 有最后期限。它通常由main函數(shù)、初始化和測(cè)試使用,并作為傳入請(qǐng)求的頂級(jí)上下文。 func Background() Context
// TODO返回一個(gè)非nil的空Context。代碼應(yīng)該使用context.TODO,當(dāng)不清楚要使用哪個(gè) // 上下文或它還不可用時(shí)(因?yàn)橹車暮瘮?shù)還沒有擴(kuò)展到接受上下文參數(shù))。 func TODO() Context
Context 層級(jí)關(guān)系
我們可以通過一個(gè)代碼片段了解 context.Context
是如何對(duì)信號(hào)進(jìn)行同步的。在這段代碼中,我們創(chuàng)建了一個(gè)過期時(shí)間為 1s 的上下文,并向上下文傳入 handle
函數(shù),該方法會(huì)使用 500ms
的時(shí)間處理傳入的請(qǐng)求:
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) } }
因?yàn)檫^期時(shí)間大于處理時(shí)間,所以我們有足夠的時(shí)間處理該請(qǐng)求,運(yùn)行上述代碼會(huì)打印出下面的內(nèi)容:
$ go run context.go
process request with 500ms
main context deadline exceeded
handle
函數(shù)沒有進(jìn)入超時(shí)的 select
分支,但是 main 函數(shù)的 select 卻會(huì)等待 context.Context
超時(shí)并打印出main context deadline exceeded
。
如果我們將處理請(qǐng)求時(shí)間增加至 1500ms,整個(gè)程序都會(huì)因?yàn)樯舷挛牡倪^期而被中止,:
$ go run context.go
main context deadline exceeded
handle context deadline exceeded
相信這兩個(gè)例子能夠幫助各位讀者理解 context.Context
的使用方法和設(shè)計(jì)原理 — 多個(gè) Goroutine 同時(shí)訂閱 ctx.Done()
管道中的消息,一旦接收到取消信號(hào)就立刻停止當(dāng)前正在執(zhí)行的工作。
context.WithCancel
函數(shù)能夠從 context.Context
中衍生出一個(gè)新的子上下文并返回用于取消該上下文的函數(shù)。一旦我們執(zhí)行返回的取消函數(shù),當(dāng)前上下文以及它的子上下文都會(huì)被取消,所有的 Goroutine 都會(huì)同步收到這一取消信號(hào)。
// WithCancel返回父對(duì)象的副本, 帶有一個(gè)新的Done通道。當(dāng)返回的cancel函數(shù)被調(diào) // 用或父上下文的Done通道被關(guān)閉時(shí),返回上下文的Done通道被關(guān)閉,以先發(fā)生的 // 情況為準(zhǔn)。 // 取消此上下文將釋放與之關(guān)聯(lián)的資源,因此代碼應(yīng)該在此上下文中運(yùn)行的操作完 // 成后立即調(diào)用cancel。 func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
除了 context.WithCancel
之外,context
包中的另外兩個(gè)函數(shù) context.WithDeadline
和 context.WithTimeout
也都能創(chuàng)建可以被取消的計(jì)時(shí)器上下文 context.timerCtx
:
context.propagateCancel
的作用是在 parent 和 child 之間同步取消和結(jié)束的信號(hào),保證在 parent 被取消時(shí),child 也會(huì)收到對(duì)應(yīng)的信號(hào),不會(huì)出現(xiàn)狀態(tài)不一致的情況。
除了 context.WithCancel
之外,context
包中的另外兩個(gè)函數(shù) context.WithDeadline
和 context.WithTimeout
也都能創(chuàng)建可以被取消的計(jì)時(shí)器上下文 context.timerCtx
:
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)) // 取消此上下文將釋放與之相關(guān)的資源,因此代碼應(yīng)該在此上下文中運(yùn)行的操作完 // 成后立即調(diào)用cancel: // func slowOperationWithTimeout(ctx context.Context) (Result, error) { // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) // defer cancel() // releases resources if slowOperation completes before timeout elapses // return slowOperation(ctx) // } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
// WithDeadline返回父上下文的副本,其截止日期調(diào)整為不晚于d。如果父上下文 // 的截止日期已經(jīng)早于d, WithDeadline(parent, d)在語義上等同于父上下 // 文。返回的上下文的Done通道在截止日期到期、返回的cancel函數(shù)被調(diào)用或父上下 // 文的Done通道被關(guān)閉時(shí)關(guān)閉,以先發(fā)生者為準(zhǔn)。 // 取消此上下文將釋放與之關(guān)聯(lián)的資源,因此代碼應(yīng)該在此上下文中運(yùn)行的操作完成 // 后立即調(diào)用cancel。 func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
在最后我們需要了解如何使用上下文傳值,context
包中的 context.WithValue
能從父上下文中創(chuàng)建一個(gè)子上下文,傳值的子上下文使用 context.valueCtx
類型:
// WithValue returns a copy of parent in which the value associated with key is // val. // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. // 提供的鍵必須具有可比性,并且不應(yīng)該是字符串類型或任何其他內(nèi)置類型,以避免 // 使用上下文的包之間發(fā)生沖突。WithValue的用戶應(yīng)該為鍵定義自己的類型。為 // 了避免在分配interface{}時(shí)分配,上下文鍵通常有具體的struct{}。或者,導(dǎo)出的 // 上下文關(guān)鍵變量的靜態(tài)類型應(yīng)該是指針或接口。 func WithValue(parent Context, key, val any) Context
關(guān)于“Golang上下文Context的常見應(yīng)用場(chǎng)景是什么”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“Golang上下文Context的常見應(yīng)用場(chǎng)景是什么”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。