Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve proper parallelism in Golang? Are goroutines parallel in versions 1.5+?

I know the differences between parallelism and concurrency. I'm looking for how to achieve parallelism in Go. I expected goroutines to be parallel, but the documentation I found appears to say otherwise.

The setting GOMAXPROCS allows us to configure the number of threads that the application can use to run in parallel. Since version 1.5, GOMAXPROCS has as value the number of cores. As far as I understand, goroutines are inherently parallel since version 1.5. Is this conclusion correct?

Every question I find on sites like StackOverflow appears to be outdated and doesn't take into account this change in version 1.5. See: Parallel processing in golang

My confusion arises from trying to test this parallelism in practice. I have tried the following code I in Go 1.10 and it doesn't run in parallel.

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func main() {

    wg.Add(2)
    go count()
    go count()
    wg.Wait()

}

func count() {
    defer wg.Done()
    for i := 0; i < 10; i++ {
        fmt.Println(i)
    }
}

Setting up GOMAXPROCS to 2 doesn't change the result. I get a concurrent program instead of a parallel one.

I'm running all my tests on an 8 core system.

Edit: For future reference,

I got carried away by this blog: https://www.ardanlabs.com/blog/2014/01/concurrency-goroutines-and-gomaxprocs.html where parallelism is achieved without much hassle in a small for-loop. The answer by @peterSO is completely valid. For some reason, in Go 1.10 I couldn't replicate the results of the blog.

like image 596
Josep Avatar asked Mar 04 '18 21:03

Josep


1 Answers

The Go Playground is a single-processor virtual machine. You are running a trivial goroutine. Toy programs run on toy machines get toy results.

Run this on a multiple CPU machine:

package main

import (
    "fmt"
    "runtime"
    "sync"
)

var wg sync.WaitGroup

func count() {
    defer wg.Done()
    for i := 0; i < 10; i++ {
        fmt.Println(i)
        i := 0
        for ; i < 1e6; i++ {
        }
        _ = i
    }
}

func main() {
    fmt.Println("Version", runtime.Version())
    fmt.Println("NumCPU", runtime.NumCPU())
    fmt.Println("GOMAXPROCS", runtime.GOMAXPROCS(0))
    wg.Add(2)
    go count()
    go count()
    wg.Wait()
}

Output:

Version go1.10
NumCPU 8
GOMAXPROCS 8
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
like image 155
peterSO Avatar answered Sep 30 '22 11:09

peterSO