count / display the number of active goroutines

30,146

There's runtime.NumGoroutine but you're approaching this wrong.

  1. Your loops will keep spawning goroutines.
  2. this will unnecessarily burn cpu cycles because of the for loop.

One approach is to use a sync.WaitGroup.

func deen(wg *sync.WaitGroup, queue chan int) {
    for element := range queue {
        fmt.Println("element is ", element)
        if element%2 == 0 {
            fmt.Println("new element is ", element)
            wg.Add(2)
            queue <- (element*100 + 11)
            queue <- (element*100 + 33)
        }
        wg.Done()
    }
}

func main() {
    var wg sync.WaitGroup
    queue := make(chan int, 10)
    queue <- 1
    queue <- 2
    queue <- 3
    queue <- 0
    for i := 0; i < 4; i++ {
        wg.Add(1)
        go deen(&wg, queue)
    }
    wg.Wait()
    close(queue)
    fmt.Println("list len", len(queue)) //this must be 0

}

playground

--- old buggy version with a race in it ---

func deen(wg *sync.WaitGroup, queue chan int) {
    for element := range queue {
        wg.Done()
        fmt.Println("element is ", element)
        if element%2 == 0 {
            fmt.Println("new element is ", element)
            wg.Add(2)
            queue <- (element*100 + 11)
            queue <- (element*100 + 33)
        }
    }
}

func main() {
    var wg sync.WaitGroup
    queue := make(chan int, 10)
    queue <- 1
    queue <- 2
    queue <- 3
    queue <- 0
    for i := 0; i < 4; i++ {
        wg.Add(1)
        go deen(&wg, queue)
    }
    wg.Wait()
    close(queue)
    fmt.Println("list is has len", len(queue)) //this must be 0
}

playground

Share:
30,146

Related videos on Youtube

meto
Author by

meto

Updated on July 01, 2022

Comments

  • meto
    meto almost 2 years

    I have a queue and a function that does both dequeueing and enqueueing. I want to make sure that the right amount of goroutines operate on the queue, as long as there is something in the list.

    This is the code I am using, but I was wondering if there is a way of printing the amount of currently active goroutines

    Link to playground

    var element int
    
    func deen(queue chan int) {
    
        element := <-queue
        fmt.Println("element is ", element)
        if element%2 == 0 {
            fmt.Println("new element is ", element)
            queue <- (element*100 + 11)
            queue <- (element*100 + 33)
        }
    }
    
    func main() {
        queue := make(chan int, 10)
        queue <- 1
        queue <- 2
        queue <- 3
        queue <- 0 
        for len(queue) != 0 {
            for i := 0; i < 2; i++ {
                go deen(queue)
            }
        }
        fmt.Scanln()
        fmt.Println("list is has len", len(queue)) //this must be 0
    
    }    
    
  • meto
    meto over 9 years
    Thanks but isn't WaitGroup to wait that something is done? I actually want to make sure they don't die too early for some external reason
  • OneOfOne
    OneOfOne over 9 years
    @meto Goroutines don't "die" like that, if a goroutine dies then your program most likely crashed, I'll add an example.
  • meto
    meto over 9 years
    that's very interesting. Just a quick follow-up question. The wg.Done part could have been placed also after the Println, but for sure before the if, right?
  • OneOfOne
    OneOfOne over 9 years
    @meto actually for that specific example it doesn't matter at all, just as long as it's outside the if.
  • meto
    meto over 9 years
    I have done a small modification (wg.Add is at the beginning of the routine). Does this seem correct to you? play.golang.org/p/KWrrLVzzBf
  • OneOfOne
    OneOfOne over 9 years
    @meto No, because wg.add wont execute until after you get out of the main for loop, goroutines don't execute immediately.
  • Sourav Prem
    Sourav Prem almost 4 years
    @OneOfOne looks like the above program panics . wg.Done() should not be right after we get the value from queue. We try and push element even after the channel has closed .
  • Sourav Prem
    Sourav Prem almost 4 years
    @OneOfOne it works when wg.Done() is moved after printf . Can anybody explain why the above program works when wg.Done() is after printf and panics if before it .Not able to understand that.
  • Brendon Whateley
    Brendon Whateley almost 3 years
    'defer wg.Done()' should be called at the start of the goroutine to ensure that the Done() only gets signaled when the routine is done running. The program might exit as soon as the wg is done waiting, cutting short the execution!