已触发截止取消的Context中,C1内的cancelCtx()有何作用?
问题:上下文已被deadline取消后,调用cancelCtx()还有什么作用?
以下程序中,C1与C2均包含select逻辑。C1中定义了1.5秒的deadline context,截止时间到达后会取消上下文,触发ctx.Done(),阻止C2读取整数,进而也会使C1触发ctx.Done()。既然上下文已被取消,那么C1中的cancelCtx()还有什么作用?
package main import ( "context" "fmt" "time" ) func main() { ctx := context.Background() C1(ctx) } func C1(ctx context.Context) { deadline := time.Now().Add(1500 * time.Millisecond) ctx, cancelCtx := context.WithDeadline(ctx, deadline) printCh := make(chan int) go C2(ctx, printCh) for num := 1; num <= 3; num++ { select { case printCh <- num: time.Sleep(1 * time.Second) case <-ctx.Done(): fmt.Printf("C1: Finished\n") } } cancelCtx() time.Sleep(100 * time.Millisecond) } func C2(ctx context.Context, printCh <-chan int) { for { select { case num := <-printCh: fmt.Printf("C2: %d\n", num) case <-ctx.Done(): if err := ctx.Err(); err != nil { fmt.Printf("C2 Error: %s\n", err) } fmt.Printf("C2: Finished\n") return } } }
回答
这个cancelCtx()的作用主要有三点:
应对循环提前完成的场景:如果C1的循环在deadline到期前就执行完毕(比如把deadline改成3秒,或者减少循环次数),此时调用
cancelCtx()会主动取消上下文,让C2立刻收到ctx.Done()信号并退出,避免C2一直阻塞在读取printCh的状态中,造成不必要的资源浪费。清理上下文关联资源:即便deadline已经触发了上下文取消,调用
cancelCtx()仍会清理context内部的相关资源,比如用于触发deadline的定时器。在Go的context实现中,定时器触发后虽会触发取消,但调用cancel能确保内部结构被彻底清理;如果该上下文存在子context,还能将取消信号传递给所有子节点,避免遗漏。遵循context使用规范:Go官方明确建议,只要调用了
context.WithDeadline、WithTimeout这类返回cancel函数的方法,无论上下文是主动还是被动取消,都必须调用cancel函数。这是一种良好的编程习惯,能有效避免复杂程序结构中潜在的资源泄漏问题。
内容的提问来源于stack exchange,提问作者user16746875
相关产品推荐
相关产品推荐

