Golang中Context包基礎知識詳解
什么是context.Context?
context.Context是Golang標準庫提供的接口(context包對此接口有多種實現(xiàn)),該接口提供了四個抽象法:
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key any) any
}
- Deadline方法,返回context.Context被取消的時間點,也就是需要完成任務的截止時間,連續(xù)調用返回相同的結果。
- Done方法, 當前context被取消后,返回的channel就會被close。如果當前context不會被取消則返回nil,連續(xù)調用返回相同的結果。
- Err方法,返回context.Context結束的錯誤
- 如果Done方法返回的channel沒有關閉,返回nil
- 如果Done方法返回的channel被關閉了,返回一個非nil的值,連續(xù)調用返回相同的結果
- context如果被取消了,返回 “context canceled”錯誤
- 如果執(zhí)行時間超過了Deadline,返回 “context deadline exceeded”錯誤
- Value方法,返回Context中key對應的value值,對于同一個context,多次調用獲取同一個key的值會返回相同的結果。
如何構造context.Context對象?
context包提供了兩個方法:
func Background() Context{}
func TODO() Context {}
- Background方法,返回一個空Context對象,所有Context對象的的源頭都應該是這個空Context對象。
- TODO方法,也是返回一個空Context對象,如果還不確定使用何種Context時,可以使用此方法創(chuàng)建的Context對象。
目前context.Background和context.TODO方法沒有太大差別,返回的都是空Context,只是在使用場景和語義上稍有不同。其他的Context都需要基于構造好的Context衍生出來,一個Context可以衍生多個子Context。
衍生Context方法
context包提供如下四個以With開頭的衍生Context的方法:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val any) Context
前三種方法的相同點都是基于parent Context生成一個新的Context并返回一個CancelFunc方法,CancelFunc調用后,當前Context和基于新Context的子Context都會被取消。不同點在于WithCancel方法返回的CancelFunc需要手動調用;WithDeadline方法可以設置一個時間點,到這個時間點后會自動調用CancelFunc,當然也可以手動調用;WithTimeout方法可以設置時長,超過指定時長后會自動調用CancelFunc,當然也可以手動調用。
WithValue方法可以生成一個綁定指定的鍵值對數據的Context,可以通過context.Value(Key) 獲取指定key的值。
使用context包需要注意的點
- 需要Context參數的方法,把Context作為第一個參數(千萬不要把Context放在結構體中,然后將結構體作為參數傳遞)。
- 使用context.Background方法構造的Context對象應該作為根Context, 用于衍生其他Context。
- 方法需要傳入的Context類型不確定的時候,傳入使用context.TODO構造的Context (千萬不要傳入nil)。
- 不要濫用context.WithValue傳遞數據,只用來傳遞必須的數據。
- Context是并發(fā)安全的,同一個Context可以傳遞給多個goroutine,可被多個goroutine同時訪問。