我认为它们是相同的,但Go内存模型中有这样一句话:如果通道是带缓冲的(例如:c = make(chan int, 1)
),那么程序就不能保证打印“hello, world” - 它可能会打印空字符串、崩溃或做其他事情。 这个说法正确吗?
虽然 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)
,则主 Go 协程只需将一个值放入缓冲区,然后继续执行 print(a)
,可能在 f()
Go 协程设置 a
为"hello,world"
之前。
但在当前代码中,主要的 Go 协程将在 c < -0
处阻塞,等待 f()
接收值后才继续打印,然后我们可以确定 a
已经设置为 "hello,world"
。
ck <- 42
)并继续执行下一条指令而无需等待某人读取通道。因此,put
Goroutine和get
Goroutine*同时访问单缓冲区通道。通道是一个队列。这两个Goroutines需要同步机制来访问缓冲区通道吗? - overexchangemake(chan int)
会创建一个无缓冲通道,make(chan int, 1)
会创建一个缓冲大小为1的通道。c <- 1
<-c
)。在缓冲通道的情况下,如果通道的缓冲区中有足够的空间存储值,则发送可以完成而不会阻塞。