我认为它们是相同的,但是The go memory model中有这样一个词:如果通道被缓冲(例如c = make(chan int, 1)
),则不能保证程序会打印“ hello,world” –它可能会打印空字符串,崩溃或执行其他操作。这是正确的吗?
虽然埃文是对的,但我认为更长的解释可能有用:
如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例程有时间设置a
之前]至"hello, world"
。
但是在当前代码中,主Go例程将在c <- 0
处阻塞,等待f()
接收到该值,然后继续打印,然后我们确定a
已经设置为"hello, world"
。
[make(chan int)
产生一个未缓冲的通道,make(chan int, 1)
产生一个缓冲为1的通道。
有关差异的说明,请参见http://golang.org/doc/effective_go.html#channels。
第一个创建一个未缓冲的通道,第二个创建一个缓冲的通道。
您尝试在通道上发送值时会看到区别:
c <- 1
[对于未缓冲的通道,此语句将阻塞,直到在通道上发生相应的接收操作为止(即<-c
)。对于缓冲的通道,如果有足够的空间将值存储在通道的缓冲区中,则发送可以完成而不会阻塞。
[在大多数情况下,无缓冲的通道是合适的,其优点是由于其阻塞性质,它们将迅速显示任何并发问题。在某些情况下,缓冲区是有意义的。
就Go内存模型而言,对于缓冲和非缓冲通道,相同的“先于发生”关系成立。尽管发送操作不会针对具有缓冲通道的相应接收而阻塞,但是仍然可以保证在接收之后运行的代码在发送之前运行的代码“之后发生”。