在Go语言中,向无缓冲通道写入/读取多个值是如何工作的呢?

huangapple go评论82阅读模式
英文:

How does writing/reading multiple values to/from a unbuffered channel work in Go?

问题

这似乎挑战了我对无缓冲通道的理解,即它只能接收一个值,然后会阻塞等待读取者读取它。

  1. 在下面的代码中,writeToChan 如何能够写入 3 个值?
  2. 更令人惊讶的是,尽管不是按照相同的顺序,这些值如何能够在稍后被读取?

来自 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.

  1. How in the following code writeToChan is able to write 3 values?
  2. 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 (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {

	ch := make(chan int)

	go writeToChan(ch)
	go rdFrmChan(ch)
	
    x := &lt;- ch
	fmt.Println(&quot;main read 1 -:&quot;,x)
	fmt.Println(&quot;main read 2 -:&quot;,&lt;-ch)
}

func writeToChan(c chan int) {
	time.Sleep(time.Second * 1)
	c &lt;- 42
	c &lt;- 27
	c &lt;- 9
}

func rdFrmChan(c chan int) {
	fmt.Println(&quot;Go routine read :&quot;, &lt;-c)
}

Output:<br>

Go routine read : 27&lt;br&gt;
main read 1 -: 42&lt;br&gt;
main read 2 -: 9&lt;br&gt;

Playground link: https://play.golang.org/p/DYzfYh-kXnC

答案1

得分: 3

每一行粘贴的摘录都由你的示例代码证明,如果你理解正在发生的事件顺序。

  1. 在启动goroutine之后,你的主例程被阻塞在读取通道c上,因为它还没有看到要读取的值。writeToChan例程在写入第一个值到通道之前等待一秒钟。

  2. goroutine rdFrmChan也被阻塞,因为它正在等待在通道ch上进行读取。

  3. 1秒钟后,当writeToChan上的睡眠时间到期时,第一次写入(c <- 42)将首先解除你的主例程的阻塞,导致值存储在x中,即42。

  4. 接下来,在下一次写入通道(c <- 27)时,rdFrmChan被解除阻塞,并看到值27。在打印该值后,该例程终止。

  5. 此时,只有一个值需要写入和一个值需要读取。来自goroutine的第三次写入(c <- 9)允许主例程作为<-ch的一部分读取该值并打印它。

英文:

Each line of the excerpt pasted is proven by your example code, if you understand the sequence of events happening.

  1. 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. The writeToChan routine waits for a second before writing the first value to the channel

  2. The goroutine rdFrmChan is also blocked, because it is waiting to read on the channel ch

  3. After 1s, when the sleep on writeToChan expires, the first write (c &lt;- 42) will unblock your main routine first, causing the value to be stored in x i.e. 42

  4. Next the rdFrmChan is unblocked on the next write to the channel (c &lt;- 27) and sees the value 27. The routine terminates at this point after printing the value

  5. At this point, there is only value to be written and one to be read. The third write (c &lt;- 9) from the goroutine allows the main routine to read the value as part of &lt;-ch and print it

huangapple
  • 本文由 发表于 2021年10月3日 01:59:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/69418943.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定