我的问题来自尝试阅读频道,如果可以的话,或者如果可以的话,使用select
声明来编写频道。
我知道像make(chan bool, 1)
那样指定的频道是缓冲的,我的问题的一部分是它与make(chan bool)
之间的区别 - this page所说的是同一个问题make(chan bool, 0)
---一个可以在其中包含0个值的通道的重点是什么?
请参阅 playground A :
chanFoo := make(chan bool)
for i := 0; i < 5; i++ {
select {
case <-chanFoo:
fmt.Println("Read")
case chanFoo <- true:
fmt.Println("Write")
default:
fmt.Println("Neither")
}
}
输出:
Neither
Neither
Neither
Neither
Neither
(删除default
案例导致死锁!!)
现在看 playground B :
chanFoo := make(chan bool, 1) // the only difference is the buffer size of 1
for i := 0; i < 5; i++ {
select {
case <-chanFoo:
fmt.Println("Read")
case chanFoo <- true:
fmt.Println("Write")
default:
fmt.Println("Neither")
}
}
B输出:
Write
Read
Write
Read
Write
就我而言, B输出就是我想要的。有什么好的无缓冲通道?我在golang.org上看到的所有示例似乎都使用它们一次发送一个信号/值(这就是我需要的) - 但是在游乐场A中,通道永远不会被读取或书面。在理解频道时,我在这里错过了什么?
答案 0 :(得分:10)
可以在其中容纳0个值的通道的重点是什么
首先我要指出这里的第二个参数意味着缓冲区大小,因此它只是一个没有缓冲区的通道(非缓冲通道)。
实际上,这就是您生成问题的原因。未缓冲的通道只有在有人阻止从中读取时才可写,这意味着你应该使用一些协同程序 - 而不是这一个。
来自无缓冲通道的接收在该通道上的发送完成之前发生。
答案 1 :(得分:4)
无缓冲通道(无容量创建)将阻止发送方,直到有人可以从中读取它们,因此为了使其按预期工作,您应该使用两个goroutine来避免同一线程中的死锁。
例如,使用此代码:http://play.golang.org/p/KWJ1gbdSqf
它还包括一个主函数检测两个goroutine何时完成的机制。
package main
import "fmt"
func send(out, finish chan bool) {
for i := 0; i < 5; i++ {
out <- true
fmt.Println("Write")
}
finish <- true
close(out)
}
func recv(in, finish chan bool) {
for _ = range in {
fmt.Println("Read")
}
finish <- true
}
func main() {
chanFoo := make(chan bool)
chanfinish := make(chan bool)
go send(chanFoo, chanfinish)
go recv(chanFoo, chanfinish)
<-chanfinish
<-chanfinish
}
它不会显示备用读取和写入,因为只要send
写入通道,它就会被阻止,然后才能打印“写入”,因此执行将移至{{1}接收频道并打印“阅读”。它将尝试再次读取该频道,但它将被阻止,执行将移至recv
。现在send
可以写第一个“写”,发送到通道(没有阻塞,因为现在有一个接收器就绪)并写第二个“写”。在任何情况下,这都不是确定性的,并且调度程序可以在任何时候将执行移动到任何其他正在运行的goroutine(至少在最新的1.2版本中)。
答案 2 :(得分:3)
无缓冲通道意味着对通道的读写操作正在阻塞。
在select
声明中:
default
个案,这种情况会发生在您的案例A中。