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:<p><pre><code> 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)
}
</code></pre>
It would be better to use time.Tick<p><pre><code> 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(".")
}
</code></pre>
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.<p><pre><code> ch := make(chan *HttpResponse, len(urls)) // buffered
</code></pre>
can just be<p><pre><code> ch := make(chan *HttpResponse)
</code></pre>
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.