协程性能

Goroutine performance

我开始学围棋了,既有趣又简单。但是使用 goroutines 我没有看到性能上的好处。

如果我尝试在 2 个函数中两次连续添加 100 万个数字:

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)
}

需要 5 毫秒。

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

当我尝试用 2 个 goroutine 做同样的事情时:

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)
}

我得到或多或少相同的结果,5 毫秒。我的电脑是 MacBook pro (Core 2 Duo)。我没有看到任何性能改进。也许是处理器?

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

在这里你可以如何使用 golangs 自己的基准测试工具来测试它:

创建一个测试文件(例如main_test.go)。

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

在那里复制以下代码或创建您自己的基准:

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()
}

运行 与:

go test -bench .

我的 Mac 结果:

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

最重要的值是 time/op。越小越好。这里3.5ns/op为正常计数,1.98ns/op为并发计数

编辑: 在这里你可以阅读 golang Testing and Benchmark.