'Stuck in infinite loop in for select in Golang

The code given below is the sample code for my use case. I want to read data from ch1 and ch2 but got stuck into infinite loop.

package main
import "fmt"

func main() {
    ch1, ch2 := func() (<-chan int, <-chan int) {
        ch_1 := make(chan int)
        ch_2 := make(chan int)

        go worker_1(ch_1, ch_2)
        go worker_2(ch_1, ch_2)

        return ch_1, ch_2
    }()

    // trying to read this way but it is not working
    for {
        select {
        case a := <-ch1:
            fmt.Println("from ch1", a)
        case a := <-ch2:
            fmt.Println("from ch2", a)
        default:
            fmt.Println("done")
        }
    }
}

func worker_1(ch1, ch2 chan int) {
    for i := 0; i < 100; i++ {
        if i%2 == 0 {
            ch1 <- i
        } else {
            ch2 <- i
        }
    }
}

func worker_2(ch1, ch2 chan int) {
    for i := 101; i < 200; i++ {
        if i%2 == 0 {
            ch1 <- i
        } else {
            ch2 <- i
        }
    }
}


Solution 1:[1]

Here is one solution:

package main

import (
    "fmt"
    "sync"
)

func main() {
    // Create channels
    ch1, ch2 := make(chan int), make(chan int)

    // Create workers waitgroup with a counter of 2
    wgWorkers := sync.WaitGroup{}
    wgWorkers.Add(2)

    // Run workers
    go worker(&wgWorkers, ch1, ch2, 0, 100)   // Worker 1
    go worker(&wgWorkers, ch1, ch2, 101, 200) // Worker 2

    // Create readers waitgroup with a counter of 2
    wgReader := sync.WaitGroup{}
    wgReader.Add(2)

    // Run readers
    go reader(&wgReader, ch1, 1) // Reader 1
    go reader(&wgReader, ch2, 2) // Reader 2

    // Wait for workers to finish
    wgWorkers.Wait()

    // Close workers channels
    close(ch1) // Makes reader 1 exit after processing the last element in the channel
    close(ch2) // Makes reader 2 exit after processing the last element in the channel

    // Wait for both readers to finish processing before exiting the program
    wgReader.Wait()
}

// Worker function definition
func worker(wg *sync.WaitGroup, ch1, ch2 chan<- int, from, to int) {
    // Decrement worker waitgroup counter by one when function returns
    defer wg.Done()
    for i := from; i < to; i++ {
        if i%2 == 0 {
            ch1 <- i
        } else {
            ch2 <- i
        }
    }
}

// Reader function definition
func reader(wg *sync.WaitGroup, ch <-chan int, chNum int) {
    // Decrement reader waitgroup counter by one when function returns
    defer wg.Done()
    // Here we iterate on the channel fed by worker 1 or worker 2.
    // for-range on a channel exits when the channel is closed.
    for i := range ch {
        fmt.Printf("from ch%d: %d\n", chNum, i)
    }
}

Explainations are in the code comments.

Solution 2:[2]

Close the channels when the workers are done. Break out of the receive loop after both channels are closed.

package main

import (
    "fmt"
    "sync"
)

func main() {
    ch1, ch2 := func() (<-chan int, <-chan int) {
        ch_1 := make(chan int)
        ch_2 := make(chan int)

        var wg sync.WaitGroup
        wg.Add(2)

        go worker_1(&wg, ch_1, ch_2)
        go worker_2(&wg, ch_1, ch_2)

        // Close channels after goroutiens complete.
        go func() {
            wg.Wait()
            close(ch_1)
            close(ch_2)
        }()

        return ch_1, ch_2
    }()

    // While we still have open channels ...
    for ch1 != nil || ch2 != nil {
        select {
        case a, ok := <-ch1:
            if ok {
                fmt.Println("from ch1", a)
            } else {
                // note that channel is closed.
                ch1 = nil
            }
        case a, ok := <-ch2:
            if ok {
                fmt.Println("from ch2", a)
            } else {
                // note that channel is closed.
                ch2 = nil
            }
        }
    }
}

func worker_1(wg *sync.WaitGroup, ch1, ch2 chan int) {
    defer wg.Done()
    for i := 0; i < 100; i++ {
        if i%2 == 0 {
            ch1 <- i
        } else {
            ch2 <- i
        }
    }
}

func worker_2(wg *sync.WaitGroup, ch1, ch2 chan int) {
    defer wg.Done()
    for i := 101; i < 200; i++ {
        if i%2 == 0 {
            ch1 <- i
        } else {
            ch2 <- i
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 A Secret Life