package main
import (
"context"
"fmt"
"time"
)
func f2(ctx context.Context) {
n := 1
for {
time.Sleep(2 * time.Second)
select {
case <-ctx.Done():
fmt.Printf("%s 结束运行\n", "f2")
return
default:
fmt.Println("f2---------------->", n)
n++
}
}
}
func f1(ctx context.Context) {
go f2(ctx)
n := 1
for {
time.Sleep(time.Second)
select {
case <-ctx.Done():
fmt.Printf("%s 结束运行\n", ctx.Err())
return
default:
fmt.Println("f1--->", n)
n++
}
}
}
func main() {
// 创建
ctx, cancel := context.WithCancel(context.Background())
go f1(ctx)
time.Sleep(time.Second * 10)
// 调用cancel方法时,会给ctx.Done这个chan就
cancel()
for{
println("main....")
time.Sleep(time.Second)
}
}
打印结果
f1---> 1
f1---> 2
f2----------------> 1
f1---> 3
f1---> 4
f2----------------> 2
f1---> 5
f1---> 6
f2----------------> 3
f1---> 7
f1---> 8
f2----------------> 4
f1---> 9
main....
f2 结束运行
context canceled 结束运行
main....
main....
main....
main....
main....
main....
main....
main....
main....
main....
main....
main....
main....
main....
main....
main....
结论:通过上面的打印记录可以知道,在主程中调用cancel
方法后,它与之相关联的f1
、f2
两个函数中ctx.Done()
这个分支的case
都触发了, 这说context
底层在我们调用cancel
方法时,往ctx.Done
这个管道中写了数据。 本例也正是用此特性完成了goroutine
的退出。
日拱一卒无有尽,功不唐捐终入海