make(chan bool) 与 make(chan bool, 1) 的行为有何不同?
Posted
技术标签:
【中文标题】make(chan bool) 与 make(chan bool, 1) 的行为有何不同?【英文标题】:How does make(chan bool) behave differently from make(chan bool, 1)? 【发布时间】:2013-12-01 05:25:07 【问题描述】:我的问题来自于尝试读取频道(如果可以),或者尝试使用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 中一样,通道永远不会被读取 or书面。在我对渠道的理解中,我在这里遗漏了什么?
【问题讨论】:
"什么是通道可以容纳0值"这里的第二个参数表示缓冲区大小,所以这只是一个没有缓冲区的通道(无缓冲通道) 如果 Read 和 Write 在不同的 goroutines 中,示例 A 可以工作。默认通道,没有容量,是无缓冲的:发送一些东西会阻塞发送方,直到接收方从通道中读取,所以你需要将两者放在不同的 goroutines 中。 @siritinga 如果您将其扩展为答案,我想就是这样。因此,非缓冲通道会阻塞,除非有人已经在等待它,而大小为 1 的缓冲通道将保持值直到有人准备好接收它。 参见:Why using unbuffered channel in the the same goroutine gives a deadlock 【参考方案1】:无缓冲的通道(无容量创建)会阻塞发送方,直到有人可以从中读取,因此为了使其按预期工作,您应该使用两个 goroutine 来避免同一线程中的死锁。
例如,使用此代码:http://play.golang.org/p/KWJ1gbdSqf
它还包括一个机制,让 main func 检测两个 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
写入通道,它就被阻塞,在它可以打印“写入”之前,所以执行转移到接收到的recv
通道并打印“读取”。它将尝试再次读取通道,但会被阻止并且执行移动到send
。现在send
可以写第一个“Write”,发送到通道(没有阻塞,因为现在有一个接收器准备好)并写第二个“Write”。在任何情况下,这都不是确定性的,调度程序可以随时将执行转移到任何其他正在运行的 goroutine(至少在最新的 1.2 版本中)。
【讨论】:
【参考方案2】:无缓冲通道意味着从通道读取和写入通道是阻塞的。
在select
声明中:
default
案例,这发生在您的案例 A 中。
【讨论】:
【参考方案3】:可以在其中容纳 0 值的通道的意义是什么
首先我要指出,这里的第二个参数表示缓冲区大小,所以它只是一个没有缓冲区的通道(无缓冲通道)。
其实这就是你的问题产生的原因。无缓冲通道仅在有人阻止读取时才可写,这意味着您将有一些协程可以使用——而不是单个协程。
另见The Go Memory Model:
来自无缓冲通道的接收发生在该通道上的发送完成之前。
【讨论】:
Bingo -- 我还没有完全了解内存模型文档。这样就搞清楚了。谢谢!以上是关于make(chan bool) 与 make(chan bool, 1) 的行为有何不同?的主要内容,如果未能解决你的问题,请参考以下文章
c:=make(chan int) 和 c:=make(chan int,1) 有啥区别?
`var a chan int` 和 `a := make(chan int)` 有啥区别?