Rob Pike在Go语言中所说的“通道的同步性质”是指什么意思?

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

What does Rob Pike mean by "the synchronization nature of the channels" in Go?

问题

这是一个代码示例,摘自“Google I/O 2012 - Go Concurrency Patterns”(幻灯片)。代码中创建了两个goroutine,分别通过joeann通道与主goroutine通信。

代码的输出结果是:

Joe 0
Ann 0
Joe 1
Ann 1
Joe 2
Ann 2
Joe 3
Ann 3
Joe 4
Ann 4
The end

Rob Pike在视频中解释道:“...我们从Joe和Ann读取一个值。由于通道的同步特性,这两个人轮流执行,不仅打印值,而且执行值。因为如果Ann准备发送一个值,但Joe还没有完成,Ann将被阻塞,等待将值传递给主函数。”

这让我感到困惑。什么是“如果Ann准备发送一个值,但Joe还没有完成,Ann将被阻塞”?我们知道,通道在两个goroutine之间建立通信并同步它们的执行。但是在这里我们创建了两个通道(joeann)。主goroutine通过joeann分别与两个新的goroutine通信。这是否意味着通道之间也具有同步特性?或者主goroutine一次只能与另一个goroutine通信?

英文:

Here is a code example taken from "Google I/O 2012 - Go Concurrency Patterns" (slides)

package main

import (
	"fmt"
	"time"
)

func main() {
	joe := boring("Joe")
	ann := boring("Ann")
	for i := 0; i < 5; i++ {
		fmt.Println(<-joe)
		fmt.Println(<-ann)
	}
	fmt.Println("The end")
}

func boring(msg string) <-chan string {
	c := make(chan string)
	go func() {
		for i := 0; ; i++ {
			c <- fmt.Sprintf("%s %d", msg, i)
			time.Sleep(time.Second)
		}
	}()
	return c
}

The output:

Joe 0
Ann 0
Joe 1
Ann 1
Joe 2
Ann 2
Joe 3
Ann 3
Joe 4
Ann 4
The end

This is the explanation by Rob Pike, the speaker (16:33 in the video): "...we're reading a value from Joe and a value from Ann. And because of the synchronization nature of the channels, the two guys are taking turns, not only in printing the values out, but also in executing them. Because if Ann is ready to send a value but Joe hasn't done that yet, Ann will still be blocked, waiting to deliver the value to main."

This confused me. What's the meaning of "if Ann is ready to send a value but Joe hasn't done that yet, Ann will still be blocked"? As we know, a channel builds the communication between two goroutines and synchronizes their executions. But we have crated two channels here (joe and ann). The main goroutine talks with two new goroutines via joe and ann, respectively. Does that mean the synchronization nature is also valid between channels? Or that the main goroutine can talk with only one other goroutine at a time?

答案1

得分: 7

这只是意味着这些通道是无缓冲的。

fmt.Println(<-joe)
fmt.Println(<-ann)

第二行在第一行完成之前无法执行。
而第一行在有东西写入joe的通道之前无法完成。

如果Ann的通道已经有一个值,那么Ann将无法写入Ann的通道。
而在joe的通道被读取之前(fmt.Println(<-joe)),该通道不会被读取(fmt.Println(<-ann))。

这两个通道是独立的(彼此不知道),但是读取操作的顺序性使得一个等待另一个先被读取。

英文:

It just means those channels are unbuffered.

    fmt.Println(&lt;-joe)
    fmt.Println(&lt;-ann)

The second line won't be able to execute before the first completes.
And the first won't complete until something writes in joe's channel.

Ann won't be able to write in Ann's channel if that channel has already a value.
And that channel won't be read (fmt.Println(&lt;-ann)) until joe's channel is read first (fmt.Println(&lt;-joe)).

Both channels are independent (unaware of each other), but the sequential nature of the read operations make one waiting for the other to be read first.

答案2

得分: 2

通道是无缓冲的。

c := make(chan string)

容量(以元素数量表示)设置通道中缓冲区的大小。如果容量为零或不存在,则通道是无缓冲的,只有在发送方和接收方都准备好时,通信才会成功。否则,通道是有缓冲的,如果缓冲区不满(发送)或不为空(接收),通信将成功进行而不会阻塞。空通道永远不会准备好进行通信。

接收将按顺序进行,先是joe,然后是ann。

fmt.Println(<-joe)
fmt.Println(<-ann)

英文:

The channels are unbuffered.

c := make(chan string)

> The capacity, in number of elements, sets the size of the buffer in
> the channel. If the capacity is zero or absent, the channel is
> unbuffered and communication succeeds only when both a sender and
> receiver are ready. Otherwise, the channel is buffered and
> communication succeeds without blocking if the buffer is not full
> (sends) or not empty (receives). A nil channel is never ready for
> communication.

The receives will be in sequence, joe followed by ann.

fmt.Println(&lt;-joe)
fmt.Println(&lt;-ann)

答案3

得分: 2

你在说“一个通道建立了两个goroutine之间的通信并同步它们的执行”时,对情况的描述是不正确的。

发生的同步是在通道内部进行的。当你尝试从通道中读取数据时,读取操作会被阻塞,直到有数据被写入到通道中。

在这个例子中有两个不同的通道,它们互相不知道对方的存在。重要的细节是这一行代码会阻塞,直到数据被写入到joe通道中:

fmt.Println(<-joe)

这就是为什么在“Joe”被打印出来之前,下一行代码无法执行的原因。

英文:

You are characterizing the situation incorrectly when you say that "a channel builds the communication between two goroutines and synchronizes their executions".

The synchronization that's happening is within the channel. When you try to read data from the channel, the read action is blocked until data has been written to the channel.

There are two different channels in this example, and neither one of them knows anything about the other. The significant detail is that this line blocks until data has been written to the joe channel:

fmt.Println(&lt;-joe)

That is what prevents the following line from being executed until "Joe" has been printed.

huangapple
  • 本文由 发表于 2015年8月22日 14:26:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/32153093.html
匿名

发表评论

匿名网友

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

确定