The sync.WaitGroup
type should encapsulate what you want to do, without needing sleep calls or busy waiting. It allows you to wait on an arbitrary number of tasks, not worrying about in which order they complete.
Taking your original example, you could alter it to use a wait group like so:
var wg sync.WaitGroup
for i := 0; i <= 10; i++ {
wg.Add(1)
go func(){
result := calculate()
c <- result
wg.Done()
}()
}
// Close the channel when all goroutines are finished
go func() {
wg.Wait()
close(c)
}()
for result := range c {
all_result = append(all_result, result...)
}