在 for 循环中写入通道会跳过迭代

writing to channel in for loop skips iterations

我正在玩频道。我在下面有这段代码,其中包含一个 for 循环。我不明白为什么程序似乎每隔一次迭代就会跳过一次,也不明白为什么最后一个值为 0。

package main

import (
    "fmt"
    "time"
)

func send(c chan int) {
    for i := 1; i < 6; i++ {
        time.Sleep(time.Second)
        c <- i
    }
    close(c)
}

func main() {
    c := make(chan int)
    go send(c)
    for range c {
        fmt.Println(<-c)
    }
}

输出:

2
4
0

你的罪魁祸首是 range c

https://play.golang.org/p/yGrUhdLAQE-

您不应在 c 上执行范围,而应使用无限循环或 case 语句。

func main() {
    c := make(chan int)
    go send(c)
    for {
        d, ok:= <- c
        if !ok{
          break
        }
        fmt.Println(d)
    }
}

不过如果你真的想在 c 上使用范围,那么你应该这样做

func main() {
    c := make(chan int)
    go send(c)
    for x := range c {
        fmt.Println(x)
    }
}

因为范围从通道中获取一个值,正确的代码应该是这样的

package main

import (
    "fmt"
    "time"
)

func send(c chan int) {
    for i := 1; i < 6; i++ {
        time.Sleep(time.Second)
        c <- i
    }
    close(c)
}

func main() {
    c := make(chan int)
    go send(c)
    for value := range c {
        fmt.Println(value)
    }
}

你应该先看看 golang 之旅。 https://tour.golang.org/concurrency/4

您同时使用两种不同的阅读方式:
for range c 从 c 频道读取一次,然后你从 <-c

的频道再次读取

如果您想写出您发送到频道的内容,只需使用以下选项之一:

for value := range c {
  fmt.Println(value)
}

OR

for {
  select {
  case value, ok := <- c:
    if !ok {
      return
    }
    fmt.Println(value)
  }
}

因为你有奇数次迭代 (1..5) 最后一个 0 出现是因为从关闭的通道读取(类型的默认值)。

如果您使用 value, ok := <-c 并且当您从它读取时通道关闭,该值将始终是默认值并且 ok 将是 false