理解go的context上下文

242 阅读1分钟

前言

在使用go开发中,有时要监听方法是否正常完成或者是否超时、取消等,可以用到go的上下文信息,context可以用来在goroutine之间传递上下文信息

context使用

WithCancel

WithCancel可以创建一个可取消的子 Context,然后当作参数传给 goroutine 使用,例如

package main  
  
import (  
"context"  
"log"  
"time"  
)  
  
func main() {  
ctx, cancel := context.WithCancel(context.Background())  
  
go func() {  
log.Println("执行开始================")  
time.Sleep(3 * time.Second)  
cancel()  
}()  
select {  
case <-ctx.Done():  
log.Println("==============执行结束")  
}  
}

输出结果为

image.png 执行了cancel()之后,阻塞就结束了

WithTimeout

WithTimeout可以创建一个可取消的子 Context

package main  
  
import (  
"context"  
"log"  
"time"  
)  
  
func main() {  
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)  
  
go func() {  
log.Println("执行开始================")  
time.Sleep(3 * time.Second)  
cancel()  
}()  
select {  
case <-ctx.Done():  
log.Println("==============执行结束", ctx.Err())  
}  
}

输出结果为

image.png 2秒之后,没有执行cancel(),就超时了

WithValue

WithValue可以用来传递上下文数据

package main  
  
import (  
"context"  
"fmt"  
"time"  
)  
  
func main() {  
ctx, cancel := context.WithCancel(context.Background())  
  
value := context.WithValue(ctx, "aa", "aaa")  
  
go run(value)  
  
time.Sleep(3 * time.Second)  
cancel()  
time.Sleep(3 * time.Second)  
  
}  
  
func run(ctx context.Context) {  
for {  
select {  
case <-ctx.Done():  
fmt.Printf("任务结束:%v\n", ctx.Value("aa"))  
return  
default:  
fmt.Printf("取到的值为: %v\n", ctx.Value("aa"))  
time.Sleep(time.Second * 2)  
}  
}  
}

输出结果为

image.png

总结

可以合理的利用context来传递goroutine之间的信息,而且context是线程安全的