在下面的程序中,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_。