c:= make(chan int)和c:= make(chan int,1)有什么区别?

问题描述 投票:4回答:3

我认为它们是相同的,但是The go memory model中有这样一个词:如果通道被缓冲(例如c = make(chan int, 1)),则不能保证程序会打印“ hello,world” –它可能会打印空字符串,崩溃或执行其他操作。这是正确的吗?

go channel
3个回答
12
投票

虽然埃文是对的,但我认为更长的解释可能有用:

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"

PlaygroundLink-WithBuffer

PlaygroundLink-WithoutBuffer


4
投票

[make(chan int)产生一个未缓冲的通道,make(chan int, 1)产生一个缓冲为1的通道。

有关差异的说明,请参见http://golang.org/doc/effective_go.html#channels


1
投票

第一个创建一个未缓冲的通道,第二个创建一个缓冲的通道。

您尝试在通道上发送值时会看到区别:

c <- 1

[对于未缓冲的通道,此语句将阻塞,直到在通道上发生相应的接收操作为止(即<-c)。对于缓冲的通道,如果有足够的空间将值存储在通道的缓冲区中,则发送可以完成而不会阻塞。

[在大多数情况下,无缓冲的通道是合适的,其优点是由于其阻塞性质,它们将迅速显示任何并发问题。在某些情况下,缓冲区是有意义的。

就Go内存模型而言,对于缓冲和非缓冲通道,相同的“先于发生”关系成立。尽管发送操作不会针对具有缓冲通道的相应接收而阻塞,但是仍然可以保证在接收之后运行的代码在发送之前运行的代码“之后发生”。

© www.soinside.com 2019 - 2024. All rights reserved.