Recently I saw a post in Reddit asking how to accomplish parallel network calls in Go.  This seemed like a really fun example of how Go makes asynchronous tasks like this readable, ie. not too brain-twisty.

The below code takes a slice of URLs and GETs their response bodies in parallel. For brevity i'll leave out the HTTP call.

Some of the essential pieces are:

sync.WaitGroup - blocks until all goroutines are finished, as it determines through the number of calls WaitGroup.Done()

go func - calls the following inline function in a new goroutine.

resultChan is a buffered channel, capacity (the second argument accounts for how many messages are expected to be sent through the channel. Note: a mismatch will cause a deadlock. This is good, ideally, everything should be accounted for.

defer executes waitGroup.Done after the enclosing function.

func CheckAll() []string {
    var waitGroup sync.WaitGroup
    urls := []string{
        "https://www.google.com",
        "https://www.microsoft.com",
        "https://www.amazon.com",
    }

    waitGroup.Add(len(urls))
    resultChan := make(chan string, len(urls))

    for _, toCheck := range urls {
        go func(url string) {
            defer waitGroup.Done()
            body := doGet(url)
            resultChan <- body
        }(toCheck)
    }

    waitGroup.Wait()
    close(resultChan)
    
    results := chanToSlice(resultChan)
    return results
}

func chanToSlice(c chan string) []string {
    s := make([]string, 0)
    for i := range c {
        s = append(s, i)
    }
    return s
}