c:=make(chan int) 和 c:=make(chan int,1) 有啥区别?
Posted
技术标签:
【中文标题】c:=make(chan int) 和 c:=make(chan int,1) 有啥区别?【英文标题】:What's the difference between c:=make(chan int) and c:=make(chan int,1)?c:=make(chan int) 和 c:=make(chan int,1) 有什么区别? 【发布时间】:2014-06-07 15:24:11 【问题描述】:我认为它们是相同的,但是The go memory model: 中有这样的词,如果通道被缓冲(例如,c = make(chan int, 1)
),那么程序将不能保证打印“hello, world”——它可能会打印空字符串、崩溃或执行其他操作。这是正确的吗?
【问题讨论】:
非常相似:***.com/questions/20041392/… 【参考方案1】:虽然 Evan 是对的,但我认为更长的解释可能会有用:
正如Effective Go 中所述,以下内容相同,并为您提供无缓冲通道:
ci := make(chan int) // unbuffered channel of integers
cj := make(chan int, 0) // unbuffered channel of integers
虽然有任何其他值会给你一个缓冲通道:
ck := make(chan int, 1) // buffered channel of integers
缓冲通道
使用缓冲通道,Go 例程可以将值放入通道 (ck <- 42
),然后继续执行下一条指令,而无需等待有人从通道读取。除非通道缓冲区已满,否则这是真的。
如果通道已满,Go 例程将等待另一个 Go 例程从通道中读取,然后才能将自己的值放在那里。
无缓冲通道
无缓冲通道将没有空间存储任何数据。因此,为了通过无缓冲通道传递值,发送 Go 例程将阻塞,直到接收 Go 例程收到该值。
因此,缓冲通道和无缓冲通道之间肯定存在差异。在内存模型案例中:
package main
import "fmt"
var c = make(chan int)
var a string
func f()
a = "hello, world"
x := <- c
fmt.Println(x)
func main()
go f()
c <- 0
print(a)
如果你有一个缓冲通道var c = make(chan int, 1)
,main()
Go 例程只会在缓冲区中放入一个值,然后继续使用print(a)
,可能在f()
Go 例程有时间设置 @ 之前987654333@转"hello, world"
。
但是在当前代码中,主 Go 例程将在 c <- 0
处阻塞,等待 f()
接收到值然后继续打印,然后我们确定 a
已经设置为 @987654338 @。
PlaygroundLink-WithBuffer
PlaygroundLink-WithoutBuffer
【讨论】:
当您说:在通道中输入一个值 (ck <- 42
),然后继续执行下一条指令无需等待某人读取频道。因此,put
Goroutine 和 get
Goroutine 可以同时访问单个缓冲通道。通道是一个队列。这两个 Goroutine 是否需要同步机制来访问缓冲通道?
@overexchange 发送和接收可以由多个 goroutine 在一个通道上完成,无需进一步同步。见最后一段:golang.org/ref/spec#Channel_types【参考方案2】:
make(chan int)
产生一个无缓冲通道,make(chan int, 1)
产生一个缓冲为 1 的通道。
请参阅http://golang.org/doc/effective_go.html#channels 了解差异的解释。
【讨论】:
【参考方案3】:第一个创建一个无缓冲通道,而第二个创建一个缓冲通道。
您可以在尝试在通道上发送值时看到差异:
c <- 1
在无缓冲通道的情况下,此语句将阻塞,直到通道上发生相应的接收操作(即<-c
)。在缓冲通道的情况下,如果通道的缓冲区中有空间存储值,则发送可以在不阻塞的情况下完成。
在大多数情况下,无缓冲通道是合适的,并且由于它们的阻塞特性,它们可以快速显示任何并发问题。但在某些情况下,缓冲区是有意义的。
就 Go 内存模型而言,缓冲通道和非缓冲通道都存在相同的“发生之前”关系。虽然发送操作不会阻塞具有缓冲通道的相应接收,但在接收之后运行的代码仍然可以保证“发生在”在发送之前运行的代码之后。
【讨论】:
我会添加我的“经验法则”,即在没有缓冲的情况下开发代码,然后再添加以提高性能。如果非缓冲代码永远不会死锁,那么缓冲代码也不会死锁,但它可能会运行得更快。以上是关于c:=make(chan int) 和 c:=make(chan int,1) 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
我可以在 go 中使用 make(chan someStruct) 吗?
make(chan bool) 与 make(chan bool, 1) 的行为有何不同?