导致上下文取消的事件序列



在下面的程序中,C1&CCD_ 2。在C1中定义了1.5秒的截止日期上下文,该上下文在截止日期之后取消上下文,导致ctx.Done(),并阻止读取C2中的整数,这将进一步取消上下文并导致C1中的ctx.Done()

如果是这种情况,那么当上下文已经被取消时,cancelCtx()C1中有什么用?

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: Finishedn")
}
}
cancelCtx()
time.Sleep(100 * time.Millisecond)
}
func C2(ctx context.Context, printCh <-chan int) {
for {
select {
case num := <-printCh:
fmt.Printf("C2: %dn", num)
case <-ctx.Done():
if err := ctx.Err(); err != nil {
fmt.Printf("C2 Error: %sn", err)
}
fmt.Printf("C2: Finishedn")
return
}
}
}

根据context.WithDeadline():的文档

取消此上下文将释放与其相关的资源,因此代码应在该上下文中运行的操作完成后立即调用cancel。

因此,最佳实践是在不再需要cancelCtx()(或您调用该函数的任何函数(时立即调用它(这对defer cancel()来说很常见,即使这意味着它被多次调用(。

在你的例子中,还有另一个原因,这可能是有益的。让我们假设截止日期是可配置的,并且已增加到5秒;现在取消上下文导致由呼叫CCD_ 14触发的CCD_。

最新更新