【发布时间】:2015-10-10 22:50:08
【问题描述】:
无缓冲通道会阻塞接收器,直到通道上有数据可用。我不清楚这种阻塞如何在同一通道上的多个接收器中表现(比如在使用 goroutine 时)。我敢肯定,只要该通道上没有发送数据,它们就会全部阻塞。
但是,一旦我向该通道发送一个值,会发生什么?哪个接收器/goroutine 将获取数据并因此解除阻塞?他们都是?排第一?随机?
【问题讨论】:
无缓冲通道会阻塞接收器,直到通道上有数据可用。我不清楚这种阻塞如何在同一通道上的多个接收器中表现(比如在使用 goroutine 时)。我敢肯定,只要该通道上没有发送数据,它们就会全部阻塞。
但是,一旦我向该通道发送一个值,会发生什么?哪个接收器/goroutine 将获取数据并因此解除阻塞?他们都是?排第一?随机?
【问题讨论】:
如果程序允许多个 goroutine 在单个通道上接收,则发送方正在广播。每个接收器应该同样能够处理数据。因此,go 运行时使用什么机制来决定众多 goroutine 接收器中的哪一个将运行 Cf 并不重要。 https://github.com/golang/go/issues/247。但是如果通道没有缓冲,每个发送的项目只会运行一个。
【讨论】:
一个随机(非确定性)的人会收到它。
见语言spec:
“选择”语句的执行分几个步骤进行:
- 对于语句中的所有情况,接收操作的通道操作数以及发送的通道和右侧表达式 语句在输入时按源顺序只计算一次 “选择”语句。结果是一组要接收的通道 from 或 send to,以及要发送的相应值。任何一方 无论哪种情况(如果有),该评估中的影响都会发生 选择通讯操作继续。上的表达 带有短变量声明的 RecvStmt 的左侧或 作业尚未评估。
- 如果一个或多个通信可以继续,则通过统一的伪随机选择选择一个可以继续的通信。 否则,如果存在默认情况,则选择该情况。如果有 不是默认情况,“select”语句阻塞,直到至少一个 的通信可以继续进行。
- 除非所选案例是默认案例,否则会执行相应的通信操作。
- 如果所选用例是带有短变量声明或赋值的 RecvStmt,则左侧表达式为 评估并分配接收到的一个(或多个)值。
- 执行所选案例的语句列表。
【讨论】:
默认情况下,goroutine 通信是synchronous 和unbuffered:在有接收者接受该值之前,发送不会完成。必须有一个接收者准备好从通道接收数据,然后发送者可以将其直接交给接收者。
所以通道发送/接收操作阻塞,直到对方准备好:
1. 通道上的发送操作会阻塞,直到同一通道有可用的接收者:如果ch 上的值没有接收者,则不能在通道中放入其他值.反之亦然:当通道不为空时,ch 不能发送新值!所以发送操作将等到ch 再次可用。
2. 通道的接收操作会阻塞,直到发送方可用于同一通道:如果通道中没有值,则接收方会阻塞。
这在以下示例中进行了说明:
package main
import "fmt"
func main() {
ch1 := make(chan int)
go pump(ch1) // pump hangs
fmt.Println(<-ch1) // prints only 0
}
func pump(ch chan int) {
for i:= 0; ; i++ {
ch <- i
}
}
因为没有接收者,goroutine 挂起并且只打印第一个数字。
为了解决这个问题,我们需要定义一个新的 goroutine,它在无限循环中从通道中读取。
func receive(ch chan int) {
for {
fmt.Println(<- ch)
}
}
然后在main():
func main() {
ch := make(chan int)
go pump(ch)
receive(ch)
}
【讨论】: