Basic channel example which is not working

func main() {
    c := make(chan int, 1)
    go send(c)
    go receive(c)
}

// send channel
func send(c chan<- int) {
    for i := 0; i < 10; i++ {
        c <- i
    }
    //close(c)               //  dont have to do it , this is not logical.
}

// receive channel
func receive(c <-chan int) {
    for v := range c {                                                                              // this is an endless loop that will keep running once the channel will have content.
        fmt.Println("Received from the channel:", v)                    this loop will stop only in case the channel will get closed. 
    }
}

what is the concept here that i am missing , why is it not showing any output ?
when i add the “close(c)” it is working, but i do not want to close any channels - want them to be open
for further use.

thanks in advance. @)
#channels #go channels #plz add hash tags - i think it will help around here.

Hi @edgarlip,

After spawning the two goroutines, main has nothing more to do and exits. When it exits, the process exits and all goroutines stop forcefully. receive() has no chance to print anything.

Here are a few ways to avoid this:

  1. The quick fix: call receive() directly (that is, remove the go keyword), so that it runs in the main flow.
  2. For more complex scenarios: add all goroutines to a WaitGroup and have main wait for the group to complete.
  3. The dirty hack: at the end of main, add a call that blocks forever, like select{}. Exit the app with Ctrl-C.
1 Like

Hi @christophberger
thanks for the quick replay !
based on you comment i have came up with this code :

func main() {
	c := make(chan int, 12)
	var wg sync.WaitGroup
	wg.Add(2)
	go send(c, &wg)
	go receive(c, &wg)
	wg.Wait()
}

// send channel
func send(c chan int, wg *sync.WaitGroup) {
	for i := 0; i < 10; i++ {
		fmt.Println("inserting stuff to channel c ", i)
		c <- i
	}
	fmt.Println("send func finished")
	close(c)
	wg.Done()
}

// receive channel
func receive(c chan int, wg *sync.WaitGroup) {
	for v := range c {
		fmt.Println("the value received from the channel:", v)
	}
	fmt.Println("receive func finished")
	wg.Done()
}

but still as u can see in the send function i see that the close() is a must ?

Yes, you need to close the channel because the range loop reads from the channel until it is closed.

In other words, closing a channel is like sending a signal to the range operator so that it knows that no more data will be coming through the channel.

2 Likes

thank you @christophberger
i understood your answer , and it was very helpful to for clearing the uncertainty.
will just add here the final code that i think that give the concept of waiting endlessly to some thing, with the
“select” functionality that you mentioned = )

func main() {
    even := make(chan int)
    odd := make(chan int)
    quit := make(chan bool)
    var wg sync.WaitGroup
    wg.Add(2)

    go send2(even, odd, quit, &wg)
    go receive2(even, odd, quit, &wg)

    wg.Wait()
    fmt.Println("*** done *** ")
}

// send channel
func send2(even chan int, odd chan int, quit chan bool, wg *sync.WaitGroup) {
    for i := 0; i < 10; i++ {
        if i%2 == 0 {
            even <- i
        } else {
            odd <- i
        }
    }
    quit <- true
    wg.Done()
}

// receive channel
func receive2(even, odd chan int, quit chan bool, wg *sync.WaitGroup) {
    for {
        select {
        case v := <-even:
            fmt.Println("the value received from the even channel:", v)
        case v := <-odd:
            fmt.Println("the value received from the odd channel:", v)
        case <-quit:
            fmt.Println("received value on channel quit !")
            wg.Done()
            return
        }
    }
}

BR,

1 Like