【发布时间】:2014-06-07 15:24:11
【问题描述】:
我认为它们是相同的,但是The go memory model: 中有这样的词,如果通道被缓冲(例如,c = make(chan int, 1)),那么程序将不能保证打印“hello, world”——它可能会打印空字符串、崩溃或执行其他操作。这是正确的吗?
【问题讨论】:
我认为它们是相同的,但是The go memory model: 中有这样的词,如果通道被缓冲(例如,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),main() Go 例程只会在缓冲区中放入一个值,然后继续使用print(a),可能在f() Go 例程有时间设置 @ 之前987654333@转"hello, world"。
但是在当前代码中,主 Go 例程将在 c <- 0 处阻塞,等待 f() 接收到值然后继续打印,然后我们确定 a 已经设置为 @987654338 @。
【讨论】:
ck <- 42),然后继续执行下一条指令无需等待某人读取频道。因此,put Goroutine 和 get Goroutine 可以同时访问单个缓冲通道。通道是一个队列。这两个 Goroutine 是否需要同步机制来访问缓冲通道?
make(chan int) 产生一个无缓冲通道,make(chan int, 1) 产生一个缓冲为 1 的通道。
请参阅http://golang.org/doc/effective_go.html#channels 了解差异的解释。
【讨论】:
第一个创建一个无缓冲通道,而第二个创建一个缓冲通道。
您可以在尝试在通道上发送值时看到差异:
c <- 1
在无缓冲通道的情况下,此语句将阻塞,直到通道上发生相应的接收操作(即<-c)。在缓冲通道的情况下,如果通道的缓冲区中有空间存储值,则发送可以在不阻塞的情况下完成。
在大多数情况下,无缓冲通道是合适的,并且由于它们的阻塞特性,它们可以快速显示任何并发问题。但在某些情况下,缓冲区是有意义的。
就 Go 内存模型而言,缓冲通道和非缓冲通道都存在相同的“发生之前”关系。虽然发送操作不会阻塞具有缓冲通道的相应接收,但在接收之后运行的代码仍然可以保证“发生在”在发送之前运行的代码之后。
【讨论】: