有時候一個功能可能涉及多個goroutine的調用,當該功能中途需要取消時,需要通知其它goroutine,這個時候Context就可以派上用場了,Context主要用來處理退出通知以及上下文數據傳遞問題。
Context之間被設計爲父子關係,要創建Context,首先要創建根節點,通常是context.Background(),該Context不能被取消,沒有值,也沒有過期時間。
有了根節點後,接下來就是創建子節點,子節點還可以繼續創建子節點,有四種方式創建子節點:WithCancel/WithDeadline/WithTimeout/WithValue,前三種方法都會返回Context和CancelFunc,父節點通過調用CancelFunc通知子節點取消,子節點通過Context提供的Done方法檢測是否被取消。WithValue將一對key-value關聯到Context,通過Context提供的Value方法獲取指定key對應的value。
WithDeadline/WithTimeout創建的Context在超時後會自動調用CancelFunc,如果調用沒有超時,需要主動調用CancelFunc以避免不必要的資源浪費,所以通常在在調用WithDeadline/WithTimeout之後會使用defer cancel()確保資源儘快釋放。
package main
import (
"context"
"fmt"
"time"
)
func say(ctx context.Context){
for{
select {
case <-ctx.Done():
return
default:
fmt.Println(ctx.Value("test"))
time.Sleep(time.Second)
}
}
}
func main(){
//5秒後調用cancelFunc取消say
ctx,cancelFunc:=context.WithCancel(context.Background())
ctx=context.WithValue(ctx,"test","hello")
go say(ctx)
time.Sleep(time.Second*5)
cancelFunc()
//2秒後調用cancelFunc取消say
ctx,_=context.WithTimeout(context.Background(),time.Second*2)
ctx=context.WithValue(ctx,"test","world")
go say(ctx)
time.Sleep(time.Second*5)
}