gpt4 book ai didi

golang 惯用的方式来停止 for

转载 作者:IT王子 更新时间:2023-10-29 01:59:14 26 4
gpt4 key购买 nike

我是 Go 的新手,所以如果我的问题的答案很明显,我提前道歉 :)

我正在计划一个读取文件并将每一行发送到 channel 的制作人,例如:

scanner := bufio.NewScanner(file)
for scanner.Scan() {
processingChan <- scanner.Text()
}

并添加一些 goroutines 来消耗这些行。

现在,我想要的是,如果任何行在 goroutine 中无法处理(假设该行包含我的业务规则的无效值),我想停止生产者循环,关闭文件(已延迟)并完成程序。

问题是:如何“通知”生产者循环/for 停止?

我发现有人建议:

for scanner.Scan() {
select {
case <- quit:
// break / return
default:
// send next line to channel
}
}

并且消费者 goroutine 会在出现任何故障时写入“退出”(或错误) channel 。

这种方法可能会解决问题,但我想知道是否有更清洁/更好或只是常见/流行的方法。

最佳答案

正确,使用退出 channel 。特别是当您已经在循环中发送到 channel 时,处理额外的 channel 很容易。但是,我不会使用您建议的形式,而是使用更简单和更安全 的版本:

for scanner.Scan() {
select {
case <- quit:
return
case processingChan <- scanner.Text():
}
}

为什么更安全?因为它不会死锁,这与您使用 default 的示例相反。您可能很幸运,从未遇到过它,但在某些情况下您会遇到。问题在于你有两个例程相互交谈,这总是需要更多的关注。考虑一下:

quit := make(chan error, 1)
prod := make(chan int)

go func() {
for n := range prod {
runtime.Gosched()
if n%66 == 0 {
quit <- errors.New("2/3 of evil")
return
}
}
}()

for n := 1; n < 1000; n++ {
select {
case <-quit:
fmt.Println(n)
return
default:
prod <- n
}
}

//https://play.golang.org/p/3kDRAAwaKR

轰!主程序试图发送到 prod channel ,但是没有人接收它;我们的消费者也有同样的问题。

向 channel 添加缓冲区也不会解决问题,但会降低它的可能性。

将前面的示例与以下更改进行比较:

select {
case <-quit:
fmt.Println(n)
return
case prod <- n:
}

//https://play.golang.org/p/pz8DMYdrVV

效果很好。

我知道有人想使用第一个选项来确保他们尽早退出,但如果您在退出前发送一两个额外的项目进行处理,这通常不是什么大问题。

关于golang 惯用的方式来停止 for,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33400530/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com