Go wait for goroutines but do stuff in the meantime

Issue

i have the following go-Code:

func execTask(input int, results chan<- int) {
    //do stuff (in my case, start process and return something)
    results <- someResult
}

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

    for _, task := range tasks {
        go execTask(task, results)
    }

    for result := range results {
        fmt.Println(result)
    }
}

For the line for result := range results { I get an Error:
fatal error: all goroutines are asleep - deadlock!. In the routine execTask I actually execute a process with os/exec, so I do not know how many results there are in results. So I have to wait for completion of all my processes, but in the meantime do something with the results. When all processes are terminated, my go-Programm may be terminated too.

How do I do this?

Thanks,
Lars

Solution

You are getting the deadlock error because you are not closing results channel. Hence, main keeps on waiting for more data on results even after all the execTask‘s have completed, and there is nothing else writing to results.

You can fix this by using sync.WaitGroup:

func main() {
    var wg sync.WaitGroup
    results := make(chan int)

    wg.Add(len(tasks))
    for _, task := range tasks {
        go func(task int) {
            defer wg.Done()
            execTask(task, results)
        }(task)
    }

    go func() {
        wg.Wait() // wait for each execTask to return
        close(results) // then close the results channel
    }

    for result := range results {
        fmt.Println(result)
    }
}

As for working on execTask results while other processes are still executing, you already have the right idea. Just work on them in the results range loop. Kick off some more goroutines in there if you want more concurrent executions.

Answered By – abhink

Answer Checked By – Dawn Plyler (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.