?
本文檔使用 PHP中文網(wǎng)手冊 發(fā)布
import "context"
概述
索引
示例
Context 包定義了上下文類型,該上下文類型跨越 API 邊界和進程之間傳遞截止期限,取消信號和其他請求范圍值。
對服務(wù)器的傳入請求應(yīng)創(chuàng)建一個 Context,對服務(wù)器的傳出調(diào)用應(yīng)接受 Context。它們之間的函數(shù)調(diào)用鏈必須傳播 Context,可以用使用 WithCancel,WithDeadline,WithTimeout 或WithValue創(chuàng)建的派生上下文替換。當(dāng) Context 被取消時,從它派生的所有 Context 也被取消。
WithCancel,WithDeadline 和 WithTimeout 函數(shù)采用Context(父級)并返回派生的Context(子級)和CancelFunc。調(diào)用 CancelFunc 將取消子對象及其子對象,刪除父對子對象的引用,并停止任何關(guān)聯(lián)的定時器。未能調(diào)用CancelFunc 會泄漏子項及其子項,直至父項被取消或計時器激發(fā)。go vet 工具檢查在所有控制流路徑上使用 CancelFuncs。
使用 Contexts 的程序應(yīng)該遵循這些規(guī)則來保持包之間的接口一致,并使靜態(tài)分析工具能夠檢查上下文傳播:
不要將上下文存儲在結(jié)構(gòu)類型中;相反,將一個 Context 明確地傳遞給每個需要它的函數(shù)。上下文應(yīng)該是第一個參數(shù),通常命名為 ctx:
func DoSomething(ctx context.Context, arg Arg) error {// ... use ctx ...}
即使函數(shù)允許,也不要傳遞nil Context。如果您不確定要使用哪個Context,請傳遞 context.TODO。
使用上下文值僅適用于傳輸進程和 API 的請求范圍數(shù)據(jù),而不用于將可選參數(shù)傳遞給函數(shù)。
相同的上下文可以傳遞給在不同 goroutine 中運行的函數(shù); 上下文對于多個 goroutine 同時使用是安全的。
有關(guān)使用Contexts 的服務(wù)器的示例代碼,請參閱https://blog.golang.org/context。
Variables(變量)
type CancelFunc
type Context
func Background() Context
func TODO() Context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
WithCancel WithDeadline WithTimeout WithValue
context.go
取消是上下文取消時 Context.Err 返回的錯誤。
var Canceled = errors.New("context canceled")
DeadlineExceeded 是 Context.Err 在上下文截止時間過后返回的錯誤。
var DeadlineExceeded error = deadlineExceededError{}
CancelFunc通知操作放棄其工作。CancelFunc不會等待工作停止。在第一次調(diào)用之后,對CancelFunc的后續(xù)調(diào)用不起作用。
type CancelFunc func()
上下文包含截止日期,取消信號以及跨越 API 邊界的其他值。
上下文的方法可能會被多個 goroutine 同時調(diào)用。
type Context interface { // 截止日期返回代表此情境完成工作的時間 // 應(yīng)該取消。 如果沒有截止日期,截止日期返回 ok == false // 組,對Deadline的連續(xù)調(diào)用返回相同的結(jié)果。 Deadline() (deadline time.Time, ok bool) // 完成后,完成返回一個關(guān)閉的頻道 // 上下文應(yīng)該取消。 如果可以的話,完成可能返回 nil(零) // 永遠不會被取消。 連續(xù)調(diào)用完成返回相同的值。 // // WithCancel 安排在完成取消時關(guān)閉完成; // WithDeadline 安排完成時間截止 // 到期; WithTimeout 安排在完成超時時關(guān)閉 // 經(jīng)過。 // // Done 提供在select語句中使用: // // // Stream 使用 DoSomething 生成值并將它們發(fā)送出去 // // 直到 DoSomething 返回一個錯誤或者 ctx.Done 關(guān)閉。 // 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: // } // } // } // // 有關(guān)如何使用的更多示例,請參閱https://blog.golang.org/pipelines // 一個Done 通道取消。 Done() <-chan struct{} // 如果Done 尚未關(guān)閉,則Err返回nil。 // 如果完成關(guān)閉,則 Err 會返回一個非零錯誤,以解釋原因: // 如果上下文被取消,則取消 // 或者如果上下文的截止時間已過,則截止時間超過。 // 在Err 返回非零錯誤之后,對Err 的連續(xù)調(diào)用返回相同的錯誤。 Err() error // 值返回與此上下文關(guān)聯(lián)的值相關(guān)的值,或者 nil // 如果沒有值與鍵關(guān)聯(lián)。 Successive 調(diào)用Value // 相同的密鑰返回相同的結(jié)果。 // // 僅將上下文值用于傳輸?shù)恼埱蠓秶鷶?shù)據(jù) // 進程和API邊界,而不是將可選參數(shù)傳遞給 // 函數(shù)。 // // 一個關(guān)鍵字標識 Context 中的特定值。 希望的Function // 在Context中存儲值通常在全局中分配一個鍵 // 然后使用該鍵作為 context.WithValue 和的參數(shù) // Context.Value, 一個密鑰可以是支持平等的任何類型; // 包應(yīng)該將鍵定義為未導(dǎo)出的類型以避免 // 碰撞 // // 定義Context鍵的軟件包應(yīng)提供類型安全的訪問器 // 對于使用該鍵存儲的值: // // pac包用戶定義了存儲在Contexts輸入中的用戶類型。 // // import "context" // // // 包用戶定義了存儲在上下文中的用戶類型。包用戶定義了存儲在上下文中的用戶類型。 // type User struct {...} // // // key(鍵)是此軟件包中定義的鍵的未導(dǎo)出類型。 // // 這可以防止與其他軟件包中定義的鍵的沖突。 // 鍵入關(guān)鍵字int // // // userKey是用戶的關(guān)鍵。上下文中的用戶值。 它是 // // 未導(dǎo)出; 客戶端使用user.NewContext和user.FromContext // // 而不是直接使用此密鑰。 // var userKey key = 0 // // // NewContext 返回一個帶有值u的新Context。 // func NewContext(ctx context.Context, u *User) context.Context { // return context.WithValue(ctx, userKey, u) // } // // // FromContext返回存儲在ctx中的User值(如果有)。 // func FromContext(ctx context.Context) (*User, bool) { // u, ok := ctx.Value(userKey).(*User) // 返回 u, ok // } Value(key interface{}) interface{}}
func Background() Context
背景返回non-nil(非零),空的 Context。它從未被取消,沒有值,也沒有最后期限。它通常由主函數(shù),初始化和測試使用,并作為傳入請求的top-level Context (頂級上下文)。
func TODO() Context
TODO 返回非零空的上下文。代碼應(yīng)該使用context.TODO,當(dāng)它不清楚使用哪個 Context或它尚不可用時(因為周圍的函數(shù)尚未擴展為接受Context參數(shù))。TODO 被靜態(tài)分析工具識別,以確定上下文是否在程序中正確傳播。
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
WithCancel 返回一個新的完成通道的父級的副本。返回的上下文的 Done 通道在返回的取消函數(shù)被調(diào)用時或父上下文的 Done 通道關(guān)閉時關(guān)閉,無論哪個先發(fā)生。
取消這個上下文會釋放與它相關(guān)的資源,所以只要完成在這個Context 中運行的操作,代碼就應(yīng)該調(diào)用 cancel。
此示例演示使用可取消上下文來防止 goroutine 泄漏。在示例函數(shù)結(jié)束時,由 gen 開始的 goroutine 將返回而不會泄漏。
package mainimport ("context""fmt")func main() {// gen在單獨的goroutine中生成整數(shù)// 將它們發(fā)送到返回的頻道。// gen的調(diào)用者需要取消一次該上下文// 他們完成消耗生成的整數(shù)不泄漏// 內(nèi)部goroutine由gen開始。 gen := func(ctx context.Context) <-chan int { dst := make(chan int) n := 1 go func() {for { select {case <-ctx.Done():return // 返回不要泄漏goroutinecase dst <- n: n++}}}()return dst} ctx, cancel := context.WithCancel(context.Background()) defer cancel() // 當(dāng)我們完成消耗整數(shù)時取消for n := range gen(ctx) { fmt.Println(n)if n == 5 {break}}}
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
WithDeadline 返回父上下文的副本,并將截止日期調(diào)整為不晚于d。如果父母的截止日期早于d,WithDeadline(parent,d)在語義上等同于父母。當(dāng)截止日期到期,返回的取消功能被調(diào)用時,或者父上下文的完成通道關(guān)閉時,返回的上下文的完成通道將關(guān)閉,以先發(fā)生者為準。
取消這個上下文會釋放與它相關(guān)的資源,所以只要完成在這個Context 中運行的操作,代碼就應(yīng)該調(diào)用cancel。
這個例子傳遞一個任意期限的上下文來告訴阻塞函數(shù),它應(yīng)該盡快放棄它的工作。
package mainimport ("context""fmt""time")func main() { d := time.Now().Add(50 * time.Millisecond) ctx, cancel := context.WithDeadline(context.Background(), d)// 即使ctx過期,最好還是調(diào)用// 取消功能無論如何。 如果不這樣做可能會保留// 上下文及其父級的活動時間超過必要時間 defer cancel() select {case <-time.After(1 * time.Second): fmt.Println("overslept")case <-ctx.Done(): fmt.Println(ctx.Err())}}
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
WithTimeout 返回 WithDeadline(parent, time.Now().Add(timeout)) 。
取消這個上下文可以釋放與它相關(guān)的資源,因此只要在這個Context 中運行的操作完成,代碼就應(yīng)該立即調(diào)用 cancel:
func slowOperationWithTimeout(ctx context.Context) (Result, error) { ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) defer cancel() // 如果slowOperation在超時之前完成,則釋放資源return slowOperation(ctx)}
這個例子傳遞一個帶有超時的上下文來告訴阻塞函數(shù),它應(yīng)該在超時過后放棄它的工作。
package mainimport ("context""fmt""time")func main() {// 傳遞帶超時的上下文告訴阻塞函數(shù)// 超時過后應(yīng)該放棄它的工作。 ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() select {case <-time.After(1 * time.Second): fmt.Println("overslept")case <-ctx.Done(): fmt.Println(ctx.Err()) // 打印"context deadline exceeded"}}
func WithValue(parent Context, key, val interface{}) Context
WithValue 返回父鍵的副本,其中與鍵關(guān)聯(lián)的值是val。
使用上下文值僅適用于傳輸進程和 API 的請求范圍數(shù)據(jù),而不用于將可選參數(shù)傳遞給函數(shù)。
提供的密鑰必須具有可比性,不應(yīng)該是字符串類型或任何其他內(nèi)置類型,以避免使用上下文的包之間發(fā)生沖突。WithValue 的用戶應(yīng)該為鍵定義他們自己的類型。為了避免在分配給接口時分配{},上下文鍵通常具有具體類型 struct {}?;蛘撸瑢?dǎo)出的上下文關(guān)鍵字變量的靜態(tài)類型應(yīng)該是指針或接口。
package mainimport ("context""fmt")func main() { type favContextKey string f := func(ctx context.Context, k favContextKey) {if v := ctx.Value(k); v != nil { fmt.Println("found value:", v)return} fmt.Println("key not found:", k)} k := favContextKey("language") ctx := context.WithValue(context.Background(), k, "Go")f(ctx, k)f(ctx, favContextKey("color"))}