在Go中处理被取消的上下文



我希望干净地处理一个可以在我的程序中取消的上下文。我将为它做一个骨架模型。

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// tracks errors or successes
completionChannel := make(chan bool)
go func1(ctx)
go func2(ctx)
numberOfFunctions := 2
for i := 0; i < numberOfFunctions; i++ {

// async signal to know if channel was successful or not
result <- completionChannel
if !result {
// should cancel all further processing of the go routines initialized above
cancel()
return
}
}
  • completionChannel填充bool (false =失败,true =成功)
  • 如果读出通道的值为假,取消所有正在运行的go例程
func func1(ctx) {
retry := true
while (retry) {
// if context is cancelled, then terminate early (how do I do this elegantly?)
err := doThing()
if err.Status == 404 {
retry = false
}
}
}

假设func1func2几乎相同。他们一遍又一遍地做一件事(想想指数后退)。如果上下文被取消,我希望防止迭代继续,以防止内存泄漏。因为读取一个没有被取消的通道是阻塞的,我如何将它添加到评论所在的位置?

编辑:

我可以添加一个非阻塞选择吗?

select {
case <-ctx.Done():
fmt.Println("returning!")
return
default:
}

查看

package main
import (
"context"
"fmt"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
wg := sync.WaitGroup{}
wg.Add(2)
go func1(ctx, cancel, &wg)
time.Sleep(time.Second * 1)
go func1(ctx, cancel, &wg)
wg.Wait()
fmt.Println("All goroutines are closed")
}
func func1(ctx context.Context, cancel context.CancelFunc, wg *sync.WaitGroup) {
select {
case <-ctx.Done():
fmt.Println("Goroutine closed by context cancel status")
wg.Done()
return
default:
status := doThing()
if status == 404 {
fmt.Println("Goroutine closed by 404 status")
cancel()
wg.Done()
return
}
}
}
func doThing() int {
return 404
}

这里我修改了doThing函数,当状态失败时测试它

我还使用sync.WaitGroup来等待所有其他例程结束

要关闭所有其他例程,您还需要为它们提供cancel函数

如果您需要跟踪状态,您可以简单地创建completionChannel,在那里推送所有状态(注意chan长度(它将是length ==例程计数))。或者使用slice将信息推送到那里,并在所有例程退出后读取它。不要在附加info - in的过程中读取它,这会导致竞争条件我认为

最新更新