It's a bit odd to do the time.Sleep in this code because it means that select is often not able to receive on the ch channel:
select {
case r := <-ch:
fmt.Printf("%s was fetched\n", r.url)
responses = append(responses, r)
if len(responses) == len(urls) {
return responses
}
default:
fmt.Printf(".")
time.Sleep(5e7)
}
It would be better to use time.Tick ticker := time.Tick(50 * time.Millisecond)
select {
case r := <-ch:
fmt.Printf("%s was fetched\n", r.url)
responses = append(responses, r)
if len(responses) == len(urls) {
return responses
}
case <-ticker:
fmt.Printf(".")
}
Also, there's no need to use a buffered channel. Each goroutine that's handling a URL get can just wait for the send on the channel before terminating. ch := make(chan *HttpResponse, len(urls)) // buffered
can just be ch := make(chan *HttpResponse)
And another thing that could be done is to not have asyncHttpGets return a slice of *HttpResponse but have it return a channel and then range over it. Then asyncHttpGets could run in its own goroutine and just close the channel when done.