英文:
Difference Ways to Read Channels
问题
我很好奇为什么从通道中读取值的不同方式会导致不同的行为。提供以下代码:
mychan := make(chan int)
go func() {
i := 0
for {
mychan <- i
<-time.After(time.Second * 1)
i++
}
}()
这个goroutine无限地向mychan
通道中发送整数序列。在这段代码之后,如果你直接使用<-mychan
读取,像这样:
fmt.Println(<-mychan)
这会打印出"0",符合预期。如果你重复执行,它会继续读取:
fmt.Println(<-mychan) // 1
fmt.Println(<-mychan) // 2
//...
然而,使用循环机制会导致无限阻塞。
for i := range mychan {
fmt.Println(i)
}
这意味着这种机制只能从已关闭的通道中读取,对吗?
然而,使用select
方法,情况变得更奇怪:
for i:=0; i<=10;i++ {
select {
case <-mychan:
fmt.Println(<-mychan)
}
}
现在它交替打印,比如1、3、5、9,每2秒一次,好像select
在mychan
和其他看不见的通道之间切换。添加另一个case
会使情况变得更有趣:
for i:=0; i<=10;i++ {
select {
case <-time.After(1 * time.Second):
fmt.Println("foo")
case <-mychan:
fmt.Println(<-mychan)
}
}
// 现在每1秒打印1、foo、3、foo、5、foo...
尽管这个问题可能对一些人来说很琐碎,但如果有人能解释和启发我,我会非常感激。
英文:
I am curious of why different ways of reading values from a channel result in different behaviors. Provided the code:
mychan := make(chan int)
go func() {
i := 0
for {
mychan <- i
<-time.After(time.Second * 1)
i++
}
}()
The goroutine "streams" a sequence of integer infinitely to a mychan
channel. After this code, if you read directly with <-mychan
like so:
fmt.Println(<-mychan)
This prints "0" as expected. If you keep repeating, it keeps reading:
fmt.Println(<-mychan) // 1
fmt.Println(<-mychan) // 2
//...
However, using the looping mechanism, it blocks infinitely.
for i := range mychan {
fmt.Println(i)
}
That means that this mechanism can only reads from a closed channel, right?
However, with select
method, thing gets wierder:
for i:=0; i<=10;i++ {
select {
case <-mychan:
fmt.Println(<-mychan)
}
}
Now it prints alternately, like 1, 3, 5, 9, ... every 2s as if select
was switching between mychan
and some other invisible channel. Adding another case
makes the case (no pun intended):
for i:=0; i<=10;i++ {
select {
case <-time.After(1 * time.Second):
fmt.Println("foo")
case <-mychan:
fmt.Println(<-mychan)
}
}
// now prints 1, foo, 3, foo, 5, foo, ... every 1s
As trivial the question as it may seems to some of you, I'd appreciate if anyone can explain and enlighten me.
答案1
得分: 4
以下是翻译好的内容:
来自以下代码的行为:
for i := range mychan {
fmt.Println(i)
}
似乎是在Go Playground上运行示例时的结果。当我在本地运行代码时,程序会无限制地每秒打印一个值。如果服务器上有一些代码分析工具可以判断代码是否会无限运行,那将很酷。
正如Volker指出的,你的第二个示例在每个打印语句中两次读取了通道。你可以使用以下代码进行修复:
for i := 0; i <= 10; i++ {
select {
case <-time.After(1 * time.Second):
fmt.Println("foo")
case x, open := <-mychan:
if !open {
return
}
fmt.Println(x)
}
}
英文:
The behavior from
for i := range mychan {
fmt.Println(i)
}
Appears to result from running examples on go playground When I ran the code locally the program prints out one value every second indefinitely. It would be cool if there is some code analysis tool they are using on the server to figure out if the code will run forever.
As Volker points out your second example is reading the channel twice per print statement. You can fix this with
for i:=0; i<=10;i++ {
select {
case <-time.After(1 * time.Second):
fmt.Println("foo")
case x, open := <-mychan:
if !open { return }
fmt.Println(x)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论