golang context 上下文管理 context.Background() 介紹


go context 上下文簡單介紹和使用

        //context.WithDeadline() // 指定一個終止時間 time
	//context.WithTimeout() // 自定義超時時間 time
	//context.WithValue() // 自定義一個鍵值對 取值 map[key]value
	//ctx,cancel:=context.WithCancel(context.Background()) // 獲取一個終止函數 

        // 設置一個50毫秒的超時
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)

        key := TraceCode("TRACE_CODE")
	traceCode, ok := ctx.Value(key).(string) // 在子goroutine中獲取trace code
	if !ok {
		fmt.Println("invalid trace code")
	}

        // 設置一個50毫秒的超時
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
	// 在系統的入口中設置trace code傳遞給后續啟動的goroutine實現日志數據聚合
	ctx = context.WithValue(ctx, TraceCode("TRACE_CODE"), "12512312234")

        d := time.Now().Add(50 * time.Millisecond)
	ctx, cancel := context.WithDeadline(context.Background(), d)

	// 盡管ctx會過期,但在任何情況下調用它的cancel函數都是很好的實踐。
	// 如果不這樣做,可能會使上下文及其父類存活的時間超過必要的時間。
	defer cancel()

	select {
	case <-time.After(1 * time.Second):
		fmt.Println("overslept")
	case <-ctx.Done():
		fmt.Println(ctx.Err())
	}

context.Context是一個接口,該接口定義了四個需要實現的方法。具體簽名如下:

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

其中:
Deadline方法需要返回當前Context被取消的時間,也就是完成工作的截止時間(deadline);
Done方法需要返回一個Channel,這個Channel會在當前工作完成或者上下文被取消之后關閉,多次調用Done方法會返回同一個Channel;
Err方法會返回當前Context結束的原因,它只會在Done返回的Channel被關閉時才會返回非空的值;
如果當前Context被取消就會返回Canceled錯誤;
如果當前Context超時就會返回DeadlineExceeded錯誤;
Value方法會從Context中返回鍵對應的值,對於同一個上下文來說,多次調用Value 並傳入相同的Key會返回相同的結果,該方法僅用於傳遞跨API和進程間跟請求域的數據;
Background()和TODO()
Go內置兩個函數:Background()和TODO(),這兩個函數分別返回一個實現了Context接口的background和todo。我們代碼中最開始都是以這兩個內置的上下文對象作為最頂層的partent context,衍生出更多的子上下文對象。

Background()主要用於main函數、初始化以及測試代碼中,作為Context這個樹結構的最頂層的Context,也就是根Context。

TODO(),它目前還不知道具體的使用場景,如果我們不知道該使用什么Context的時候,可以使用這個。

background和todo本質上都是emptyCtx結構體類型,是一個不可取消,沒有設置截止時間,沒有攜帶任何值的Context。

官方案例

var (
	ctx    context.Context
	cancel context.CancelFunc
)

func handleSearch(w http.ResponseWriter, req *http.Request) {
	// ctx 上下文管理 簡單案例演示
	timeout, err := time.ParseDuration(req.FormValue("timeout"))
	if err == nil {
		// 初始化 上下文並獲取對象
		ctx, cancel = context.WithTimeout(context.Background(), timeout)
	} else {
		ctx, cancel = context.WithCancel(context.Background())
	}
	// 延時關閉
	defer cancel()
}

demo代碼演示二:


var wg sync.WaitGroup

func handleSearch(ctx context.Context) {

	for {
		time.Sleep(time.Second)
		fmt.Println("working……")
		select {
		case <-ctx.Done():
			return
		default:
		}
	}
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	wg.Add(1) //添加

	// 如何實現go 子程序優雅的退出
	go handleSearch(ctx)
	// 案例監聽5秒
	time.Sleep(time.Second * 5)
	// 連續5秒都沒完成則自動退出
	cancel()  // 退出
	wg.Wait() // 等待結束
	fmt.Println("over")
}

推薦以參數的方式顯示傳遞Context
以Context作為參數的函數方法,應該把Context作為第一個參數。
給一個函數方法傳遞Context的時候,不要傳遞nil,如果不知道傳遞什么,就使用context.TODO()
Context的Value相關方法應該傳遞請求域的必要數據,不應該用於傳遞可選參數
Context是線程安全的,可以放心的在多個goroutine中傳遞


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM