context上下文的意思, 可以用來(lái)做超時(shí)管理 禀崖,context 可以設(shè)置截止日期箍铭,超時(shí)或調(diào)用取消函數(shù)來(lái)通知所有使用任何派生 context 的函數(shù)來(lái)停止運(yùn)行并返回。
1.創(chuàng)建 context
(1) ctx := context.Background()
返回一個(gè)空 context蜜唾。這只能用于高等級(jí)(在 main 或頂級(jí)請(qǐng)求處理中)用于派生杂曲。
(2) ctx := context.TODO() Context
返回也是空context,與Bg的區(qū)別在于靜態(tài)分析工具可以使用它來(lái)驗(yàn)證 context 是否正確傳遞袁余,這是一個(gè)重要的細(xì)節(jié)擎勘,因?yàn)殪o態(tài)分析工具可以幫助在早期發(fā)現(xiàn)潛在的錯(cuò)誤,并且可以連接到 CI/CD 管道颖榜。
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
2.使用context
(1) context.WithValue(parent Context, key, val interface{}) (ctx Context, cancel CancelFunc)
此函數(shù)接收 context 并返回派生 context棚饵,其中值 val 與 key 關(guān)聯(lián),并通過(guò) context 樹與 context 一起傳遞朱转。這意味著一旦獲得帶有值的 context蟹地,從中派生的任何 context 都會(huì)獲得此值。不建議使用 context 值傳遞關(guān)鍵參數(shù)藤为,而是函數(shù)應(yīng)接收簽名中的那些值,使其顯式化夺刑。
ctx := context.WithValue(context.Background(), key, "test")
(2) context.WithCancel(parent Context) (ctx Context, cancel CancelFunc)
返回派生 context 和取消函數(shù)缅疟。只有創(chuàng)建它的函數(shù)才能調(diào)用取消函數(shù)來(lái)取消此 context分别。如果您愿意,可以傳遞取消函數(shù)存淫,但是耘斩,永遠(yuǎn)不要傳遞取消函數(shù)。
ctx, cancel := context.WithCancel(context.Background())
(3) context.WithDeadline(parent Context, d time.Time) (ctx Context, cancel CancelFunc)
此函數(shù)返回其父項(xiàng)的派生 context桅咆,當(dāng)截止日期超過(guò)或取消函數(shù)被調(diào)用時(shí)括授,該 context 將被取消。例如岩饼,您可以創(chuàng)建一個(gè)將在以后的某個(gè)時(shí)間自動(dòng)取消的 context荚虚,并在子函數(shù)中傳遞它。當(dāng)因?yàn)榻刂谷掌诤谋M而取消該 context 時(shí)籍茧,獲此 context 的所有函數(shù)都會(huì)收到通知去停止運(yùn)行并返回版述。
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2 * time.Second))
(4) context.WithTimeout(parent Context, timeout time.Duration) (ctx Context, cancel CancelFunc)
此函數(shù)類似于 context.WithDeadline。不同之處在于它將持續(xù)時(shí)間作為參數(shù)輸入而不是時(shí)間對(duì)象寞冯。此函數(shù)返回派生 context渴析,如果調(diào)用取消函數(shù)或超出超時(shí)持續(xù)時(shí)間,則會(huì)取消該派生 context吮龄。
ctx, cancel := context.WithTimeout(context.Background(), 2 * time.Second)
Demo:
一個(gè)超時(shí)的例子:
package main
import (
"context"
"fmt"
"math/rand"
"time"
)
/* Context 可以用來(lái)做超時(shí)管理
*
*/
func sleepRandom(fromFunction string, ch chan int){
defer func(){fmt.Println(fromFunction, "sleepRandom complete")}()
seed := time.Now().UnixNano()
r := rand.New(rand.NewSource(seed))
randomNumber := r.Intn(100)
sleeptime := randomNumber + 100
fmt.Println(fromFunction, "starting sleep for", sleeptime, "ms")
time.Sleep(time.Duration(sleeptime) * time.Millisecond)
fmt.Println(fromFunction, "Waking up, slept for", sleeptime, "ms")
if ch != nil{
ch <- sleeptime
}
}
func sleepRandomContext(ctx context.Context, ch chan bool){
defer func(){
fmt.Println("sleepRandomContext complete")
ch <- true
}()
sleeptimeChan := make(chan int)
go sleepRandom("sleepRandomContext", sleeptimeChan)
select{
case <-ctx.Done():
fmt.Println("sleepRandomContext: Time to return")
case sleeptime := <- sleeptimeChan:
fmt.Println("sleep for ", sleeptime, "ms")
}
}
func doWorkContext(ctx context.Context){
ctxWithTimeout, cancelFunction := context.WithTimeout(ctx, time.Duration(100) * time.Millisecond)
fmt.Println("begin")
time.Sleep(1 * time.Second)
defer func(){
fmt.Println("doWorkContext complete")
cancelFunction()
}()
ch := make(chan bool)
go sleepRandomContext(ctxWithTimeout, ch)
select {
case <- ctx.Done():
fmt.Println("doWorkContext: Time to return")
case <- ch:
fmt.Println("sleepRandomContext returns")
}
}
func main(){
ctx := context.Background()
/*
* Context 可以用來(lái)做超時(shí)管理俭茧,當(dāng)context關(guān)閉的時(shí)候,函數(shù)也跟著關(guān)閉了
*/
//cancelFunction 取消函數(shù)
//可以直接取消當(dāng)前的context,context -> nil
ctxWithCancel, cancelFunction := context.WithCancel(ctx)
defer func(){
fmt.Println("Main Defer: canceling context")
cancelFunction()
}()
go func(){
time.Sleep(1 * time.Second)
//sleepRandom("Main", nil)
cancelFunction()
fmt.Println("Main Sleep complete. canceling context")
}()
doWorkContext(ctxWithCancel)
}