The Fool
The Fool

Reputation: 20467

writing to channel in for loop skips iterations

I am playing with channels. I have this code below which contains a for loop. I don't understand why the program seem to skip every other iteration and also why the last value is 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)
    }
}

Output:

2
4
0

Upvotes: 1

Views: 1084

Answers (3)

Pongi
Pongi

Reputation: 59

You should check out the golang tour first. https://tour.golang.org/concurrency/4

You use two different kind of reading in the same time:
for range c reads from c channel once, then you read again from the channel with <-c

if you would like to write out what you sent to the channel simply use one of the followings:

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

OR

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

Because you have odd number of iterations (1..5) the last 0 appears because of the read from the closed channel (default value of type).

If you use value, ok := <-c and the channel is closed when you read from it, the value always will be the default value and ok will be false.

Upvotes: 2

sonus21
sonus21

Reputation: 5388

Your culprit is range c

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

You should not do range on c instead you should use infinite for loop or case statement.

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

Though if you really want to use range over c then you should do something like this

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

Upvotes: 1

Pizza lord
Pizza lord

Reputation: 763

because range take a value from the channel the correct code would look like this

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)
    }
}

Upvotes: 3

Related Questions