我试图了解缓冲频道的工作方式,并为其编写代码段

package main

import (
    "fmt"
)

func squares(c chan int) {
    for i := 0; i < 4; i++ {
        num := <-c
        fmt.Println(num * num)
    }
}

func main() {
    fmt.Println("main() started")
    c := make(chan int, 3)
    
        go squares(c)

    c <- 1
    c <- 2
    c <- 3
    c <- 4 // blocks here

    fmt.Println("main() stopped")
}

根据我期望该程序的表现方式,主goroutine启动并持续到c <-4,直到c <-4被阻止,并且控件转移到Square Goroutine(由于缓冲区容量为3)。正方形goroutine中的循环一直持续到第四次迭代,此时通道为空。空通道上的读取操作正在阻止,因此控件返回到主goroutine。那时,对频道的写操作(C <-4)被执行,我们打印"main() stopped"并结束程序。

这意味着我希望输出是

main() started
1
4
9
main() stopped

但是我得到了一个输出,

main() started
1
4
9
16
main() stopped

如何?我是否缺少有关channel如何工作的东西?

分析解答

那不是频道的工作方式。

Goroutines同时运行。这意味着,当goroutine发送到缓冲通道时,另一个goroutine等待从该频道接收的gor可以立即接收它。它不会等待频道填充。

至于程序的结束,当您将最后一个号码发送到频道时,无法保证Goroutine会在程序结束之前拾起并打印输出,因为您不在等待Goroutine完成。因此,通过运气,它可以运行并打印输出。将在其他执行中不会发生其他执行,并且该程序在Goroutine可以打印输出之前终止。