Goroutine performance

Issue

I have started to learn Go, it’s fun and easy. But working with goroutines I have seen little benefit in performance.

If I try to sequentially add 1 million numbers two times in 2 functions:

package main

import (
    "fmt"
    "time"
)

var sumA int
var sumB int

func fSumA() {
    for i := 0; i < 1000000; i++ {
        sumA += i
    }
}

func fSumB() {
    for i := 0; i < 1000000; i++ {
        sumB += i
    }
}

func main() {
    start := time.Now()
    fSumA()
    fSumB()
    sum := sumA + sumB
    fmt.Println("Elapsed time", time.Since(start))
    fmt.Println("Sum", sum)
}

It takes 5 ms.

MacBook-Pro-de-Pedro:hello pedro$ ./bin/hello
Elapsed time 5.724406ms
Suma total 999999000000
MacBook-Pro-de-Pedro:hello pedro$ ./bin/hello
Elapsed time 5.358165ms
Suma total 999999000000
MacBook-Pro-de-Pedro:hello pedro$ ./bin/hello
Elapsed time 5.042528ms
Suma total 999999000000
MacBook-Pro-de-Pedro:hello pedro$ ./bin/hello
Elapsed time 5.469628ms
Suma total 999999000000

When I try to do the same thing with 2 goroutines:

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

var sumA int
var sumB int

func fSumA() {
    for i := 0; i < 1000000; i++ {
        sumA += i
    }
    wg.Done()
}

func fSumB() {
    for i := 0; i < 1000000; i++ {
        sumB += i
    }
    wg.Done()
}

func main() {
    start := time.Now()
    wg.Add(2)
    go fSumA()
    go fSumB()
    wg.Wait()
    sum := sumA + sumB
    fmt.Println("Elapsed time", time.Since(start))
    fmt.Println("Sum", sum)
}

I get more or less the same result, 5 ms. My computer is a MacBook pro (Core 2 Duo). I don’t see any performance improvement. Maybe is the processor?

MacBook-Pro-de-Pedro:hello pedro$ ./bin/hello
Elapsed time 5.258415ms
Suma total 999999000000
MacBook-Pro-de-Pedro:hello pedro$ ./bin/hello
Elapsed time 5.528498ms
Suma total 999999000000
MacBook-Pro-de-Pedro:hello pedro$ ./bin/hello
Elapsed time 5.273565ms
Suma total 999999000000
MacBook-Pro-de-Pedro:hello pedro$ ./bin/hello
Elapsed time 5.539224ms
Suma total 999999000000

Solution

Here how you can test this with the golangs own benchmark tool:

Create a test go file (e.g. main_test.go).

Note: _test.go has to be the file ending!

Copy the following code there or create your own Benchmarks:

package main

import (
    "sync"
    "testing"
)

var GlobalInt int

func BenchmarkCount(b *testing.B) {
    var a, c int
    count(&a, b.N)
    count(&c, b.N)
    GlobalInt = a + c // make sure the result is actually used
}

func count(a *int, max int) {
    for i := 0; i < max; i++ {
        *a += i
    }
}

var wg sync.WaitGroup

func BenchmarkCountConcurrent(b *testing.B) {
    var a, c int
    wg.Add(2)
    go countCon(&a, b.N)
    go countCon(&c, b.N)
    wg.Wait()

    GlobalInt = a + c // make sure the result is actually used
}

func countCon(a *int, max int) {
    for i := 0; i < max; i++ {
        *a += i
    }
    wg.Done()
}

Run with:

go test -bench .

Result on my Mac:

$ go test -bench .
BenchmarkCount-8                500000000            3.50 ns/op
BenchmarkCountConcurrent-8      2000000000           1.98 ns/op
PASS
ok      MyPath/MyPackage        6.309s

Most important value is the time/op. The smaller the better. Here 3.5 ns/op for normal counting, 1.98 ns/op for concurrent counting.

EDIT:
Here you can read up on golang Testing and Benchmark.

Answered By – TehSphinX

Answer Checked By – Candace Johnson (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.