缓冲通道的行为与我在 Go 中的期望有何不同?

问题描述 投票:0回答:2

我试图了解缓冲通道的工作原理并为其编写代码片段

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, which at that point gets blocked and the control goes to square goroutine (as the buffer capacity is 3). The loop in the squares goroutine continues till 4th iteration at which point the channel is empty. A read operation on an empty channel is blocking and so the control goes back to main goroutine. At that point the write operation to the channel (c<-4) gets executed, we print "main() stopped" and the program ends.

意味着我期望输出是,

main() started
1
4
9
main() stopped

但是我得到一个输出,

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

如何?我是不是漏掉了一些有关渠道具体运作方式的信息?

go concurrency goroutine channels
2个回答
1
投票

这不是渠道的运作方式。

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

至于程序的结束,当你将最后一个数字发送到通道时,并不能保证 goroutine 会在程序结束之前将它捡起来并打印输出,因为你不是在等待 goroutine 完成。因此,幸运的是,它运行并打印了输出。在没有发生这种情况的情况下还会有其他执行,并且程序在 goroutine 可以打印输出之前终止。


-1
投票

节目有比赛。

main()
函数可以在 goroutine 从通道接收到第一个值后继续执行过去的
c <- 4
main()
发送第四个值后,goroutine 可以执行完成。

打点电话。睡觉观察比赛。如果 goroutine 在 receive 后休眠,那么

main()
很可能赢得比赛并在打印任何方块之前退出。

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

https://go.dev/play/p/x-3wiWwFQGj

如果

main()
在最后一次发送后休眠,那么 goroutine 很可能赢得比赛并打印出四个方块。

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

    go squares(c)

    c <- 1
    c <- 2
    c <- 3
    c <- 4 

    time.Sleep(100)
    fmt.Println("main() stopped")
}

https://go.dev/play/p/HIpRKdbA5qa

这些只是程序的两个可能输出。 goroutine 可以在打印

main() stopped
之后和 main 退出之前打印一个值。 goroutine 可以打印零到四个值。

我在上面说“可能”是因为睡眠并不能确保所描述的结果。

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