欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang上下文Context的常見應用場景

 更新時間:2023年04月14日 11:23:39   作者:chinusyan  
Golang?context主要用于定義超時取消,取消后續(xù)操作,在不同操作中傳遞值。本文通過簡單易懂的示例進行說明,感興趣的可以了解一下

Context

// A Context carries a deadline, a cancellation signal, and other values across
// API boundaries.
// Context包含一個截止日期、一個取消信號和跨越API邊界的其他值。
// Context's methods may be called by multiple goroutines simultaneously.
// Context的方法可以被多個goroutine同時調用。
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下做完工作應該取消的時間。當沒有設置截止日
	// 期時,Deadline返回ok==false。連續(xù)調用Deadline返回相同的結果。
	Deadline() (deadline time.Time, ok bool)
	// Done返回一個通道,當在該上下文所做的工作應該取消時,該通道關閉。如果這
	// 個上下文永遠不能取消,Done可能返回nil。對Done的連續(xù)調用返回相同的值。
	// Done通道的關閉可以在cancel函數返回之后異步發(fā)生
	// WithCancel安排Done在cancel被調用時關閉;WithDeadline安排Done在截止
	// 日期到期時關閉;WithTimeout設置Done在超時后關閉。
	// 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返回與上下文相關的key的值,如果沒有與key相關的值則返回nil。連
	// 續(xù)調用具有相同鍵的Value返回相同的結果。
	// 僅對傳輸到進程和API邊界的請求范圍內的數據使用上下文值,而不是將可選參
	// 數傳遞給函數。
	// key 標識上下文中的特定值。希望在Context中存儲值的函數通常在全局變量
	// 中分配一個鍵,可以使用該鍵作為context.WithValue和
	// Context.Value的參數。 key 可以是支持相等的任何類型;包應該將key 定義
	// 為未導出的類型,以避免沖突。
	// 定義Context 鍵的包應該為使用該鍵存儲的值提供類型安全的訪問器:
	// 	// 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

// emptyCtx永遠不會取消,沒有值,也沒有截止日期。它不是struct{},因為這
// 種類型的變量必須有不同的地址。
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

// cancelCtx可以被取消。當取消時,它還取消實現(xiàn)canceler的所有子對象。
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
}

canceler接口

// 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{}
}

timerCtx

// 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()
}

valueCtx

// 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,這兩個方法都會返回預先初始化好的私有變量 backgroundtodo,它們會在同一個 Go 程序中被復用:

Background()

// Background返回一個非nil的空Context。它永遠不會被取消,沒有values,也沒
// 有最后期限。它通常由main函數、初始化和測試使用,并作為傳入請求的頂級上下文。
func Background() Context

TODO()

// TODO返回一個非nil的空Context。代碼應該使用context.TODO,當不清楚要使用哪個
// 上下文或它還不可用時(因為周圍的函數還沒有擴展到接受上下文參數)。
func TODO() Context

Context 層級關系

我們可以通過一個代碼片段了解 context.Context 是如何對信號進行同步的。在這段代碼中,我們創(chuàng)建了一個過期時間為 1s 的上下文,并向上下文傳入 handle 函數,該方法會使用 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)
	}
}

因為過期時間大于處理時間,所以我們有足夠的時間處理該請求,運行上述代碼會打印出下面的內容:

$ go run context.go
process request with 500ms
main context deadline exceeded

handle 函數沒有進入超時的 select 分支,但是 main 函數的 select 卻會等待 context.Context 超時并打印出main context deadline exceeded。

如果我們將處理請求時間增加至 1500ms,整個程序都會因為上下文的過期而被中止,:

$ go run context.go
main context deadline exceeded
handle context deadline exceeded

相信這兩個例子能夠幫助各位讀者理解 context.Context 的使用方法和設計原理 — 多個 Goroutine 同時訂閱 ctx.Done() 管道中的消息,一旦接收到取消信號就立刻停止當前正在執(zhí)行的工作。

取消信號

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

WithCancel()

// WithCancel返回父對象的副本, 帶有一個新的Done通道。當返回的cancel函數被調
// 用或父上下文的Done通道被關閉時,返回上下文的Done通道被關閉,以先發(fā)生的
// 情況為準。
// 取消此上下文將釋放與之關聯(lián)的資源,因此代碼應該在此上下文中運行的操作完
// 成后立即調用cancel。
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) 

除了 context.WithCancel 之外,context 包中的另外兩個函數 context.WithDeadline context.WithTimeout 也都能創(chuàng)建可以被取消的計時器上下文 context.timerCtx

context.propagateCancel 的作用是在 parent 和 child 之間同步取消和結束的信號,保證在 parent 被取消時,child 也會收到對應的信號,不會出現(xiàn)狀態(tài)不一致的情況。

除了 context.WithCancel 之外,context 包中的另外兩個函數 context.WithDeadline context.WithTimeout 也都能創(chuàng)建可以被取消的計時器上下文 context.timerCtx

WithTimeout()

// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout))
// 取消此上下文將釋放與之相關的資源,因此代碼應該在此上下文中運行的操作完
// 成后立即調用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()

// WithDeadline返回父上下文的副本,其截止日期調整為不晚于d。如果父上下文
// 的截止日期已經早于d, WithDeadline(parent, d)在語義上等同于父上下
// 文。返回的上下文的Done通道在截止日期到期、返回的cancel函數被調用或父上下
// 文的Done通道被關閉時關閉,以先發(fā)生者為準。
// 取消此上下文將釋放與之關聯(lián)的資源,因此代碼應該在此上下文中運行的操作完成
// 后立即調用cancel。
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)

傳值方法

在最后我們需要了解如何使用上下文傳值,context 包中的 context.WithValue 能從父上下文中創(chuàng)建一個子上下文,傳值的子上下文使用 context.valueCtx 類型:

WithValue()

// 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.
// 提供的鍵必須具有可比性,并且不應該是字符串類型或任何其他內置類型,以避免
// 使用上下文的包之間發(fā)生沖突。WithValue的用戶應該為鍵定義自己的類型。為
// 了避免在分配interface{}時分配,上下文鍵通常有具體的struct{}?;蛘?,導出的
// 上下文關鍵變量的靜態(tài)類型應該是指針或接口。
func WithValue(parent Context, key, val any) Context 

到此這篇關于Golang上下文Context的常見應用場景的文章就介紹到這了,更多相關Golang Context內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Go語言中interface語法與使用詳解

    Go語言中interface語法與使用詳解

    Go語言里面設計最精妙的應該算interface,它讓面向對象,內容組織實現(xiàn)非常的方便,下面這篇文章主要給大家介紹了關于Go語言中interface語法與使用的相關資料,需要的朋友可以參考下
    2022-07-07
  • Go語言程序開發(fā)gRPC服務

    Go語言程序開發(fā)gRPC服務

    這篇文章主要為大家介紹了Go語言程序開發(fā)gRPC服務,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Go基于GORM 獲取當前請求所執(zhí)行的 SQL 信息(思路詳解)

    Go基于GORM 獲取當前請求所執(zhí)行的 SQL 信息(思路詳解)

    這篇文章主要介紹了Go基于GORM 獲取當前請求所執(zhí)行的 SQL 信息(思路詳解),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • 詳解Go中defer與return的執(zhí)行順序

    詳解Go中defer與return的執(zhí)行順序

    Go?defer中改變return的值會生效嗎,這就設計到了GO語言中defer與return哪個先執(zhí)行的問題了,下面小編就通過簡單的示例來和大家講講吧
    2023-07-07
  • Go gRPC環(huán)境安裝教程示例詳解

    Go gRPC環(huán)境安裝教程示例詳解

    這篇文章主要為大家介紹了Go gRPC環(huán)境安裝的教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • 淺析Go語言中數組的這些細節(jié)

    淺析Go語言中數組的這些細節(jié)

    這篇文章主要為大家詳細介紹了Go語言中數組一些細節(jié)的相關資料,文中的示例代碼講解詳細,對我們學習Go語言有一定的幫助,需要的可以了解一下
    2022-11-11
  • golang如何實現(xiàn)抓取IP地址的蜘蛛程序詳解

    golang如何實現(xiàn)抓取IP地址的蜘蛛程序詳解

    這篇文章主要給大家介紹了關于利用golang如何實現(xiàn)抓取IP地址的蜘蛛程序的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-07-07
  • Golang 模塊引入及表格讀寫業(yè)務快速實現(xiàn)示例

    Golang 模塊引入及表格讀寫業(yè)務快速實現(xiàn)示例

    這篇文章主要為大家介紹了Golang模塊引入及表格讀寫業(yè)務的快速實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • Go語言中字符串的查找方法小結

    Go語言中字符串的查找方法小結

    這篇文章主要介紹了Go語言中字符串的查找方法小結,示例的main函數都是導入strings包然后使用其中的方法,需要的朋友可以參考下
    2015-10-10
  • 通過與Java功能上的對比來學習Go語言

    通過與Java功能上的對比來學習Go語言

    這篇文章主要介紹了通過與Java功能上的對比來學習Go語言的相關資料,需要的朋友可以參考下
    2023-02-02

最新評論