没有等待组,将数据从不同的go例程写入相同的chanel可以正常工作

When writing data into same channel using multiple go routines with waitgroup after waiting wg.Wait() getting exception saying all go routines are asleep or deedlock.

package main

import (
    "fmt"
    "runtime"
    "sync"
)

var wg sync.WaitGroup

func CreateMultipleRoutines() {
    ch := make(chan int)

    for i := 0; i < 10; i++ { // creates 10 go routines and adds to waitgroup
        wg.Add(1)
        go func() {
            for j := 0; j < 10; j++ {
                ch <- j
            }
            wg.Done() // indication of go routine is done to main routine
        }()
    }

    fmt.Println(runtime.NumGoroutine())
    wg.Wait()           //wait for all go routines to complete
    close(ch)           // closing channel after completion of wait fo go routines
    for v := range ch { // range can be used since channel is closed
        fmt.Println(v)
    }
    fmt.Println("About to exit program ...")
}

When tried to implement this without waitgroup I am able to read data from channel by looping exact number of times data pushed to channel but i cant range since there will be panic when we close channel. here is the example code

package main

import (
    "fmt"
    "runtime"
)

func main() {
    ch := make(chan int)


    for i := 0; i < 10; i++ { // creates 10 go routines and adds to waitgroup
        go func(i int) {
            for j := 0; j < 10; j++ {
                ch <- j * i
            }
        }(i)
    }

    fmt.Println(runtime.NumGoroutine())

    for v := 0; v < 100; v++ {
        fmt.Println(<-ch)
    }
    fmt.Println("About to exit program ...")
}

I want to understand why waitgroup in wait state is still waiting even though all go routines are signalled Done() which inturn makes number of go routines to zero

By default a chan holds no items, so all go routines are blocked on sending, until something reads from it. They never actually reach the wg.Done() statement.

A solution would be to close the channel in it's own go routine. Wrap your wg.Wait() and close(ch) lines like this:

go func() {
    wg.Wait() //wait for all go routines to complete
    close(ch) // closing channel after completion of wait fo go routines
}()

Then you can range over the channel, which will only close after all of the sending go routines have finished (and implicitly all values have been received).

I think your original code has some problems.

  1. You are closing the channel before reading from it.
  2. You are not getting the advantage of using 10 goroutines because of your channel is 1 "sized". So one goroutine is producing one result per once.

My solution would be to spawn a new goroutine to monitor if the 10 goroutines finished its jobs. There you will use your WaitGroup.

Then the code would be like:

package main

import (
    "fmt"
    "runtime"
    "sync"
)

var wg sync.WaitGroup

func main() {
    ch := make(chan int, 10)

    for i := 0; i < 10; i++ { // creates 10 go routines and adds to waitgroup
        wg.Add(1)
        go func() {
            for j := 0; j < 10; j++ {
                ch <- j
            }
            wg.Done() // indication of go routine is done to main routine
        }()
    }

    go func(){
        wg.Wait()
        close(ch)
    }()

    fmt.Println(runtime.NumGoroutine())
    for v := range ch { // range can be used since channel is closed
        fmt.Println(v)
    }
    fmt.Println("About to exit program ...")
}