What am I missing on concurrency?

Issue

I have a very simple script that makes a get request and then does some thing with the response. I have 2 version one using a go routine and one without I bencharmaked both and there was no difference in speed. Here is a dumb down version of what I’m doing:

Regular Version:

func main() {
    url := "http://finance.yahoo.com/q?s=aapl"

    for i := 0; i < 250; i++ {
        resp, err := http.Get(url)
        if err != nil {
            fmt.Println(err)
        }

        fmt.Println(resp.Status)
    }
}

Go Routine:

func main() {
    url := "http://finance.yahoo.com/q?s=aapl"

    for i := 0; i < 250; i++ {
        wg.Add(1)
        go run(url, &wg)
        wg.Wait()
    }
}

func run(url string, wg *sync.WaitGroup) {
    defer wg.Done()
    resp, err := http.Get(url)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(resp.Status)
}

In most cases when I used a go routine the program took longer to execute. What concept am I missing to understand using concurrency efficiently?

Solution

The main problem with your example is that you’re calling wg.Wait() within the for loop. This causes execution to block until you the deferred wg.Done() call inside of run. As a result, the execution isn’t concurrent, it happens in a goroutine but you block after starting goroutine i and before starting i+1. If you place that statement after the loop instead like below then your code won’t block until after the loop (all goroutines have been started, some may have already completed).

func main() {
    url := "http://finance.yahoo.com/q?s=aapl"

    for i := 0; i < 250; i++ {
        wg.Add(1)
        go run(url, &wg)
        // wg.Wait() don't wait here cause it serializes execution
    }
    wg.Wait() // wait here, now that all goroutines have been started
}

Answered By – evanmcdonnal

Answer Checked By – Jay B. (GoLangFix Admin)

Leave a Reply

Your email address will not be published.