Golang中如何持续读取Channel的默认值
Golang中如何持续读取Channel的默认值 我有一个goroutine会从通道读取数据,还有一个主routine会向通道写入数据。
package main
import "time"
func main() {
var dataCh = make(chan int)
go readDataCh(dataCh)
for i := 0; i < 10; i++ {
dataCh <- i
}
close(dataCh)
time.Sleep(10 * time.Second)
}
func readDataCh(ints chan int) {
time.Sleep(10 * time.Second)
for {
select {
case d, _ := <-ints:
println(":data is there", d)
/* if !ok{
return
}*/
}
}
}
问题:
- 为什么在读取完写入通道的数据后,它会持续输出默认值(对于int是0,对于string是"")?
- 我在一个地方读到过,其中提到关闭通道会停止操作并退出。但它并没有起到相同的作用。你能帮我解决这个问题吗?
更多关于Golang中如何持续读取Channel的默认值的实战教程也可以访问 https://www.itying.com/category-94-b0.html
非常感谢伊万帮助我理解。
我的问题是,如果我能用“ok”来检查通道是否关闭,那么为什么通道必须发送默认值呢?抱歉,这一点我仍然不太明白。因为我仍然觉得,通道关闭或打开的消息就足以让我退出工作协程了。
每当case被执行时,我们都会用“ok”来检查通道是否关闭(就像你在case语句中检查的那样)。
关闭的通道之所以会反复传递相同的默认值,是因为可能有多个消费者从同一个通道消费数据。他们需要收到通道关闭的通知,而正如克里斯托夫所解释的,这是通过发送一个带有布尔值的默认值来实现的,该布尔值指示通道的状态。在极端情况下,只要通道有效,您就可以将其传递到多个地方并监听它。即使在通道关闭很久之后也是如此。
祝您有美好的一天。
@Gowtham_Girithar: 你在第一篇文章中的代码在 for 循环内有一个 select:
for {
select {
case d ,_:= <-ints:
println(":data is there", d)
/* if !ok{
return
} */
}
}
但在你引用的网站上,它只是一个 select:
select {
case <-shutdown:
done <- i
}
在你列出的网站示例中,启动了 5 个 goroutine,它们都等待 shutdown 通道传来一个值。如果你向该通道发送值,则每发送一个值,其中一个 goroutine 就会完成。如果你关闭该通道,那么所有 goroutine 会立即从 shutdown 通道接收到一个默认值,并将它们的 id(即 i 变量)发送到 done 通道。
实际上,它们并非在监听默认值,而是在持续接收值,直到收到一个通知通道关闭的消息。但请试想,这个通知消息会是什么呢?最合理的选择是发送默认值以及一个额外的值,用以表明该消息实际上是一个关闭通知。你无法想象仅凭一个值就能表示关闭,因为任何值本身都可能是一个有效的消息。例如,对通道进行 range 操作是一种语法糖,它替代了我之前示例中的写法:
for msg, ok := <-ch; ok; {
fmt.Println(msg)
}
在你的第二个问题中,你假设会使用 range。是的,range 能够优雅且透明地处理通道的关闭。但这并非你唯一可能使用或需要的语法。请看下面这个使用 for…select 重写的示例:
package main
import (
"fmt"
"sync"
)
func main() {
ch := make(chan int)
close(ch)
const N = 10
var wg sync.WaitGroup
wg.Add(N)
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
defer fmt.Println("exiting")
for {
select {
// 假设在此 case 之前还有其他 case
case msg, ok := <-ch:
if !ok {
return
}
fmt.Println(msg)
}
}
}()
}
wg.Wait()
}
一个受单个关闭操作影响多个通道的典型例子是工作池模式。任务通过一个单一的通道分发,由 N 个工作协程监听。当任务流水线关闭时,所有工作协程退出。它们中的每一个都必须能够监听到这同一个通道的关闭(当然,其他设计也是可能的,甚至可能更好)。

