为什么我的代码中没有这个缓冲通道块?

我正在学习 Go 语言。有人可以在这里解释输出吗?


package main


import "fmt"


var c = make(chan int, 1)


func f() {


    c <- 1


    fmt.Println("In f()")

}


func main() {

    go f()


    c <- 2

    fmt.Println(<-c)

    fmt.Println(<-c)


}

输出:


In f()

2

1


Process finished with exit code 0

为什么“In f()”出现在“2”之前?如果在“2”之前打印“In f()”,则缓冲通道应该阻塞。但这并没有发生,为什么?


白衣染霜花
浏览 108回答 2
2回答

幕布斯7119047

导致此事件发生的事件顺序如下:触发 goroutine。写入2频道。通道的容量现已耗尽。从通道中读取并输出结果。写入1频道。从通道中读取并输出结果。导致死锁的事件顺序如下:触发 goroutine。写入1频道。通道的容量现已耗尽。写入2频道。由于通道的缓冲区已满,因此阻塞。您提供的输出似乎表明goroutine首先完成并且程序没有死锁,这与上述两种情况的解释相矛盾。这是发生的事情:触发 goroutine。写入2频道。2从频道读取。写入1频道。输出In f()。输出2从通道接收到的数据。1从频道读取。输出1从通道接收到的数据。请记住,除非您以编程方式强制执行它们,否则您对 goroutine 的调度没有任何保证。当您启动一个 goroutine 时,该 goroutine 的第一个代码实际执行的时间以及在此之前启动代码的进度是未定义的。请注意,由于您的代码依赖于特定的事件顺序,因此它被该定义破坏,只是明确地说。此外,在程序中的任何时候,调度程序都可以决定在不同的 goroutine 之间切换。甚至单行也fmt.Printtln(<-c)包含多个步骤,并且在每个步骤之间都可能发生切换。

慕哥9229398

要重现块,您必须多次运行该代码,这是最简单的测试方法。你没有运气的障碍。但不能保证:var c = make(chan int, 1)func f() {&nbsp; &nbsp; c <- 1&nbsp; &nbsp; fmt.Println("In f()")}func TestF(t *testing.T) {&nbsp; &nbsp; go f()&nbsp; &nbsp; c <- 2&nbsp; &nbsp; fmt.Println(<-c)&nbsp; &nbsp; fmt.Println(<-c)}并使用命令运行:go test -race -count=1000 -run=TestF -timeout=4s测试次数在哪里count。它再现了对我的阻塞。提供超时以不等待默认 10 分钟
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go