如何知道上下文是不是已被取消?
Posted
技术标签:
【中文标题】如何知道上下文是不是已被取消?【英文标题】:How to know if the context has been cancelled?如何知道上下文是否已被取消? 【发布时间】:2021-10-07 13:30:23 【问题描述】:如何知道上下文是否已被取消?
在下面的示例代码中,
有 2 个任务。 如果这些任务中的任何一个先完成,我想通过上下文取消了解其他任务。 作为示例的一部分,task2 将始终首先完成(在 task1 之前)。package main
import (
"context"
"fmt"
"time"
)
func task2(ctx context.Context, ch chan int)
for i := 0; i <= 10; i++
if ctx.Err() != nil
// In case task1 completes first,
// I want to print this error. How do I reach this block?
fmt.Println("Cancelled 2", ctx.Err())
fmt.Println("Task2 ===== ", i)
time.Sleep(1 * time.Second)
if i == 2
ch <- 2
func task1(ctx context.Context, ch chan int)
for i := 0; i <= 10; i++
if ctx.Err() != nil
// In case task2 completes first,
// I want to print this error. How do I reach this block?
fmt.Println("Cancelled 1", ctx.Err())
fmt.Println("Task1 ----- ", i)
time.Sleep(1 * time.Second)
if i == 5
ch <- 1
func main()
ctx, cancel := context.WithCancel(context.Background())
ch := make(chan int)
go task1(ctx, ch)
go task2(ctx, ch)
d := <-ch
cancel() // If either of task1 or task2 completes, invoke the cancel() func
fmt.Println("Task which completed first: ", d)
【问题讨论】:
【参考方案1】:由于您的频道没有缓冲,task1
将在 ch <- 1
中死锁,因为您在 main()
中的 ch
上只有一次阅读。要解决此问题,您可以将其转换为检查 ctx.Done()
的选择语句:
if i == 5
select
case ch <- 1:
return
case <-ctx.Done():
fmt.Println("Cancelled 1", ctx.Err())
return
您可以在task2
中执行相同操作。
请注意,当main()
终止时,任何仍然存在的 go 例程都会随之终止,无论它们在做什么。如果您不希望这样,则需要提供额外的同步,例如使用 sync.WaitGroup
,如下所示:
func a(wg *sync.WaitGroup)
defer wg.Done()
time.Sleep(time.Second)
fmt.Println("a is done!")
func b(wg *sync.WaitGroup)
defer wg.Done()
time.Sleep(time.Second*2)
fmt.Println("b is done, too!")
func main()
wg := &sync.WaitGroup
wg.Add(2)
go a(wg)
go b(wg)
wg.Wait()
fmt.Println("Everyone is done! We can terminate without interrupting anyone.")
【讨论】:
以上是关于如何知道上下文是不是已被取消?的主要内容,如果未能解决你的问题,请参考以下文章