英文:
How does writing/reading multiple values to/from a unbuffered channel work in Go?
问题
这似乎挑战了我对无缓冲通道的理解,即它只能接收一个值,然后会阻塞等待读取者读取它。
- 在下面的代码中,
writeToChan
如何能够写入 3 个值? - 更令人惊讶的是,尽管不是按照相同的顺序,这些值如何能够在稍后被读取?
来自 https://golang.org/doc/effective_go#channels 的摘录:
接收者总是阻塞,直到有数据可接收。如果通道是无缓冲的,发送者会阻塞,直到接收者接收到值。如果通道有缓冲,发送者只会阻塞,直到值被复制到缓冲区;如果缓冲区已满,这意味着等待直到某个接收者取走一个值。
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go writeToChan(ch)
go rdFrmChan(ch)
x := <- ch
fmt.Println("main read 1 -:",x)
fmt.Println("main read 2 -:",<-ch)
}
func writeToChan(c chan int) {
time.Sleep(time.Second * 1)
c <- 42
c <- 27
c <- 9
}
func rdFrmChan(c chan int) {
fmt.Println("Go routine read :", <-c)
}
输出:
Go routine read : 27
main read 1 -: 42
main read 2 -: 9
Playground 链接:https://play.golang.org/p/DYzfYh-kXnC
英文:
This seems to challenge my understanding of unbuffered channel, which is that it can only take one value and then it would block for a reader to read it.
- How in the following code
writeToChan
is able to write 3 values? - More so surprisingly, how are those values available to be read later albeit not in same order?
An excerpt from https://golang.org/doc/effective_go#channels
> Receivers always block until there is data to receive. If the channel is unbuffered, the sender blocks until the receiver has received the value. If the channel has a buffer, the sender blocks only until the value has been copied to the buffer; if the buffer is full, this means waiting until some receiver has retrieved a value.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go writeToChan(ch)
go rdFrmChan(ch)
x := <- ch
fmt.Println("main read 1 -:",x)
fmt.Println("main read 2 -:",<-ch)
}
func writeToChan(c chan int) {
time.Sleep(time.Second * 1)
c <- 42
c <- 27
c <- 9
}
func rdFrmChan(c chan int) {
fmt.Println("Go routine read :", <-c)
}
Output:<br>
Go routine read : 27<br>
main read 1 -: 42<br>
main read 2 -: 9<br>
Playground link: https://play.golang.org/p/DYzfYh-kXnC
答案1
得分: 3
每一行粘贴的摘录都由你的示例代码证明,如果你理解正在发生的事件顺序。
-
在启动goroutine之后,你的主例程被阻塞在读取通道
c
上,因为它还没有看到要读取的值。writeToChan
例程在写入第一个值到通道之前等待一秒钟。 -
goroutine
rdFrmChan
也被阻塞,因为它正在等待在通道ch
上进行读取。 -
1秒钟后,当
writeToChan
上的睡眠时间到期时,第一次写入(c <- 42
)将首先解除你的主例程的阻塞,导致值存储在x
中,即42。 -
接下来,在下一次写入通道(
c <- 27
)时,rdFrmChan
被解除阻塞,并看到值27。在打印该值后,该例程终止。 -
此时,只有一个值需要写入和一个值需要读取。来自goroutine的第三次写入(
c <- 9
)允许主例程作为<-ch
的一部分读取该值并打印它。
英文:
Each line of the excerpt pasted is proven by your example code, if you understand the sequence of events happening.
-
After the goroutines are started, your main routine is blocked reading from the channel
c
, as it is yet to see a value to read. ThewriteToChan
routine waits for a second before writing the first value to the channel -
The goroutine
rdFrmChan
is also blocked, because it is waiting to read on the channelch
-
After 1s, when the sleep on
writeToChan
expires, the first write (c <- 42
) will unblock your main routine first, causing the value to be stored inx
i.e. 42 -
Next the
rdFrmChan
is unblocked on the next write to the channel (c <- 27
) and sees the value 27. The routine terminates at this point after printing the value -
At this point, there is only value to be written and one to be read. The third write (
c <- 9
) from the goroutine allows the main routine to read the value as part of<-ch
and print it
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论