以下 Go 程序的输出是什么

问题描述 投票:0回答:1
package main

import "fmt"

func consume(ch chan int) {
    for {
        select {
        case num := <-ch:
            fmt.Printf("%d ", num)
            break
        }
    }
}

func main() {
    ch := make(chan int)
    go consume(ch)

    for i := 0; i < 5; i++ {
        ch <- i
    }

}

每次我们运行这个程序时,输出不是固定的,即 0 1 2 3 4 吗?

for-select 语句不断等待通道发送数据,但由于通道是无缓冲的,它会不会阻塞

consume()
go-routine 的执行?

我认为当数字被发送到通道时,go例程将以完全相同的顺序打印它们(0 1 2 3 4),因为for-select语句将被阻塞,直到它收到一个数字。

我不清楚这里发生了什么。请帮忙!

go concurrency channel
1个回答
0
投票

在提供的代码中,不保证输出固定为“0 1 2 3 4”。让我们来分析一下发生了什么:

main函数创建一个无缓冲的通道ch。 然后它通过调用 Consumer(ch) 启动一个 Goroutine。 在主 Goroutine 中,它将 0 到 4 之间的整数发送到通道 ch。 在消费 goroutine 中,有一个无限循环,其中有一条 select 语句等待从通道接收数据。 现在,行为可能会有所不同:

由于通道是无缓冲的,向其发送数据将会阻塞,直到有接收器准备好接收数据为止。在这种情况下,consume 是接收者。 然而,consume goroutine 有一个带有 select 语句的循环。当从通道接收到一个值时,会立即打印该值,然后执行循环中断语句,从而退出 select 并退出循环。 因此,虽然您可能期望输出按顺序排列 (0 1 2 3 4),但无法保证主 goroutine 和消费 goroutine 之间的执行顺序。在主 Goroutine 完成将所有值发送到通道之前,消费 Goroutine 可能会开始消费并打印值(尽管不能保证)。

在实践中,由于 goroutine 的并发性质和 Go 运行时的非确定性调度行为,您可能会看到类似 0 2 1 3 4 的输出或任何其他可能的排列。

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