尝试实现死锁时无限循环零

Suh*_*pta 8 channel go

以下代码保持打印0.

package main

import (
    "fmt"
)

func main() {

    c := make(chan int)

    go func() {
        for i := 0; i < 10; i++ {
            c <- i // INPUT
        }
        close(c)
    }()

    for {
        fmt.Print(<-c) // RECEIVER; OUTPUT
    }
}
Run Code Online (Sandbox Code Playgroud)

从我的理解,它应该打印09然后继续无限循环.为什么要继续印刷zero

icz*_*cza 12

你的理解(几乎)是正确的,除了主goroutine中的无限循环不会阻挡但是会无情地接收和打印.

您开始的goroutine会在通道上发送数字0,1,... 9,然后将其关闭.并且从封闭信道接收不会阻塞,相反,它可以立即进行,并且它产生信道的元素类型的零值,这是0该类型的int.这在规范:接收运营商中说明:

nil频道接收永久阻止.关闭的通道上的接收操作总是可以立即进行,在接收到任何先前发送的值之后产生元素类型的零值.

所以你确切地知道你应该做什么.首先它打印数字0..9,然后保持打印0速度非常快(没有任何延迟),所以可能你甚至没有注意到初始0..9数字.

略微修改您的示例,以便在15次迭代后退出主goroutine中的循环将立即显示发生的情况:

c := make(chan int)
go func() {
    for i := 0; i < 10; i++ {
        c <- i // INPUT
    }
    close(c)
}()

for i := 0; i < 15; i++ {
    fmt.Print(<-c) // RECEIVER; OUTPUT
}
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上试试):

012345678900000
Run Code Online (Sandbox Code Playgroud)

如果您的目标是在处理(打印)所有已发送的号码后退出,请使用for range频道上的:

for i := range c {
    fmt.Print(i) // RECEIVER; OUTPUT
}
Run Code Online (Sandbox Code Playgroud)

如果您的目标是在处理完这10个号码后阻止新号码可用,则不要关闭该频道.这样下一个接收操作就会阻塞.在这种情况下,原始循环和for range循环都可以工作,但for range更好,因为如果/当通道关闭时总是退出.

查看此问题并记住通道公理:非初始化通道的行为如何?