本文已参加「新人创作礼」活动,一起开启掘金创作之路。
go context 四种衍生用法
我在这就不具体的讲解他的用法\含义\以及低层原理,大家可以百度搜索学习,我在这直接上代码,简单实例
WithCancel
func main() {
//根context
background := context.Background()
ctx, cancel := context.WithCancel(background)
go watch(ctx, "【监控1】")
go watch(ctx, "【监控2】")
go watch(ctx, "【监控3】")
time.Sleep(5 * time.Second)
fmt.Println("可以了,通知监控停止")
cancel()
//为了检测监控过是否停止,如果没有监控输出,就表示停止了
time.Sleep(5 * time.Second)
}
func watch(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "监控退出,停止了...")
return
default:
fmt.Println(name ,"goroutine监控中...")
time.Sleep(time.Second)
}
}
/**
例子中启动了3个监控goroutine进行不断的监控,每一个都使用Context进行跟踪,
当我们使用cancel函数通知取消时候,这3个 goroutine都会被结束。
所有基于这个context或者衍生出来的子Context都会收到通知,
这样就可以进行清理操作最终释放goroutine了
*/
}
WithDeadline
func main() {
ctx := context.Background()
t := time.Now().Add(5 * time.Second)
//cc, cancelFunc := context.WithDeadline(ctx, t)
cc, _ := context.WithDeadline(ctx, t)
go watch(cc, "【监控1】")
go watch(cc, "【监控2】")
//cancelFunc()
time.Sleep(6 * time.Second)
}
func watch(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "超时或者主动退出,停止了...")
return
default:
fmt.Println(name, "goroutine监控中...")
time.Sleep(time.Second)
}
}
}
/**
这个方法,就有两种结束的方法,一种是time设定的时间到了,自动停止,
一种是,提前调用cancelFunc(),提前结束
*/
留一个探讨问题,如果用下面的方法,会不会打印 -- "超时退出,停止了""
func watch2(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "超时或者主动退出,停止了...")
return
case <-time.After(2 * time.Second):
fmt.Println(name, "超时退出,停止了...")
return
default:
fmt.Println(name, "goroutine监控中...")
time.Sleep(time.Second)
}
}
}
WithTimeout
func main() {
background := context.Background()
timeoutContext, _ := context.WithTimeout(background, 5*time.Second)
go watch(timeoutContext,"[监控一]")
go watch(timeoutContext,"[监控二]")
fmt.Println("现在开始等待8秒,time=", time.Now().Unix())
time.Sleep(8 * time.Second)
//fmt.Println("等待8秒结束,准备调用cancel()函数,发现两个子协程已经结束了,time=", time.Now().Unix())
//cancelFunc()
}
func watch(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "监控退出,停止了...")
return
default:
fmt.Println(name, "goroutine监控中...")
time.Sleep(time.Second)
}
}
}
/**
这个和哪个WithDeadline 用法差不多,具体细节以及低层代码原理,就不在这解析了
*/
WithValue
/**
这个还是比较有意思的
key val 都是 interface
*/
func main() {
background := context.Background()
ctx1 := context.WithValue(background, "01", "hello")
test2(ctx1)
}
func test1(ctx context.Context) context.Context{
ctx02 := context.WithValue(ctx, "02", "world")
return ctx02
}
func test2(ctx context.Context) {
fmt.Println(ctx.Value("01"))
fmt.Println(ctx.Value("02"))
}
/**
输出:
hello
<nil>
*/
func main() {
background := context.Background()
ctx1 := context.WithValue(background, "01", "hello")
ctx2 := test1(ctx1)
test2(ctx2)
}
func test1(ctx context.Context) context.Context{
ctx02 := context.WithValue(ctx, "02", "world")
return ctx02
}
func test2(ctx context.Context) {
fmt.Println(ctx.Value("01"))
fmt.Println(ctx.Value("02"))
}
/**
输出:
hello
world
*/