阅读频道的不同方法

时间:2016-12-22 14:51:41

标签: go concurrency channel

我很好奇为什么从频道读取值的不同方式会导致不同的行为。提供代码:

mychan := make(chan int)

go func() {
    i := 0
    for {
        mychan <- i
        <-time.After(time.Second * 1)
        i++
    }
}()

goroutine将一个无限整数序列“流”到mychan个通道。在此代码之后,如果您直接阅读<-mychan,请执行以下操作:

fmt.Println(<-mychan)

按预期打印“0”。如果你不断重复,它会继续阅读:

fmt.Println(<-mychan)    // 1
fmt.Println(<-mychan)    // 2
//...

但是,使用循环机制,它会无限制地阻塞。

for i := range mychan {
    fmt.Println(i)
}

这意味着这种机制只能从封闭的通道读取,对吗? 但是,使用select方法,事情变得更加严峻:

for i:=0; i<=10;i++ {
    select {
    case <-mychan:
        fmt.Println(<-mychan)
    }
}

现在它交替打印,如1,3,5,9,...每2秒,就好像selectmychan和其他一些不可见的通道之间切换一样。添加另一个case就可以了(没有双关语):

for i:=0; i<=10;i++ {
    select {
    case <-time.After(1 * time.Second):
        fmt.Println("foo")
    case <-mychan:
        fmt.Println(<-mychan)
    }
}

// now prints 1, foo, 3, foo, 5, foo, ... every 1s

对于你们中的一些人来说,这似乎是微不足道的问题,如果有人能够解释和启发我,我会很感激。

1 个答案:

答案 0 :(得分:4)

来自

的行为
for i := range mychan {
    fmt.Println(i)
}

go playground上运行示例时出现的结果当我在本地运行代码时,程序每秒打印一个值无限期。如果他们在服务器上使用一些代码分析工具来确定代码是否会永远运行,那将会很酷。

正如Volker指出的那样,你的第二个例子是每个打印语句读取两次通道。您可以使用

解决此问题
for i:=0; i<=10;i++ {
    select {
    case <-time.After(1 * time.Second):
        fmt.Println("foo")
    case x, open := <-mychan:
        if !open { return }
        fmt.Println(x)
    }
}