为什么goroutines这么慢?

时间:2016-08-19 18:07:15

标签: go

我昨天用几乎相同的代码发布了一个问题,询问如何在可变参数函数中进行并发。解决之后,我预计程序与一台发电机的运行时间几乎相同,与30+一样。它似乎并非如此。

我看到的时间是一台发电机,大约5ms。使用下面的代码中的内容,150毫秒。 (出于某种原因,play.golang显示0)。

为什么慢?我的期望是,对于多个goroutines,它需要相当长的时间。旋转goroutines有什么关系?

package main

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

func main() {
    t := time.Now()
    _ = fanIn(
        generator(4, 5, 6, 7),
        generator(1, 2, 6, 3, 7),
        generator(12, 15, 33, 40, 10),
        generator(18, 13, 20, 40, 15),
        generator(100, 200, 64000, 3121, 1237),
        generator(4, 5, 6, 7),
        generator(1, 2, 6, 3, 7),
        generator(12, 15, 33, 40, 10),
        generator(18, 13, 20, 40, 15),
        generator(100, 200, 64000, 3121, 1237),
        generator(4, 5, 6, 7),
        generator(1, 2, 6, 3, 7),
        generator(12, 15, 33, 40, 10),
        generator(18, 13, 20, 40, 15),
        generator(100, 200, 64000, 3121, 1237),
        generator(4, 5, 6, 7),
        generator(1, 2, 6, 3, 7),
        generator(12, 15, 33, 40, 10),
        generator(18, 13, 20, 40, 15),
        generator(100, 200, 64000, 3121, 1237),
        generator(4, 5, 6, 7),
        generator(1, 2, 6, 3, 7),
        generator(12, 15, 33, 40, 10),
        generator(18, 13, 20, 40, 15),
        generator(100, 200, 64000, 3121, 1237),
        generator(4, 5, 6, 7),
        generator(1, 2, 6, 3, 7),
        generator(12, 15, 33, 40, 10),
        generator(18, 13, 20, 40, 15),
        generator(100, 200, 64000, 3121, 1237),
        generator(4, 5, 6, 7),
        generator(1, 2, 6, 3, 7),
        generator(12, 15, 33, 40, 10),
        generator(18, 13, 20, 40, 15),
        generator(100, 200, 64000, 3121, 1237),
    )

    fmt.Println(time.Now().Sub(t))
}

func generator(nums ...int) <-chan int {
    out := make(chan int, 10)
    go func() {
        defer close(out)
        for _, v := range nums {
            out <- v
        }
    }()
    return out
}

func fanIn(in ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int, 10)
    wg.Add(len(in))

    go func() {
        for _, v := range in {
            go func(ch <-chan int) {
                defer wg.Done()
                for val := range ch {
                    out <- val
                }
            }(v)
        }

    }()
    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}

1 个答案:

答案 0 :(得分:2)

go rungo build(编译时)之间略有不同:
对于我17ms(在2个核心上)和3ms(在8个核心上)go1.7 amd64

go rungo build之间的差异:
951.0543ms-934.0535ms = 17.0008ms (在2个核心上)
575.3447ms-572.3914ms = 2.9533ms (在8个核心上)

8个核心与2个核心之间的差异go build
 934.0535ms-572.3914ms = 361.6621ms

要获得良好的基准统计数据,请使用大量样本 尝试更新到最新的Go版本(1.7)。

尝试使用此工作示例代码,并将结果与​​这些输出进行比较:

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

func main() {
    t := time.Now()
    cs := make([]<-chan int, 1000)
    for i := 0; i < len(cs); i++ {
        cs[i] = generator(rand.Perm(10000)...)
    }
    ch := fanIn(cs...)
    fmt.Println(time.Now().Sub(t))

    is := make([]int, 0, len(ch))
    for v := range ch {
        is = append(is, v)
    }
    fmt.Println("len=", len(is))
}

func generator(nums ...int) <-chan int {
    out := make(chan int, len(nums))
    go func() {
        defer close(out)
        for _, v := range nums {
            out <- v
        }
    }()
    return out
}

func fanIn(in ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int, 10)
    wg.Add(len(in))

    go func() {
        for _, v := range in {
            go func(ch <-chan int) {
                defer wg.Done()
                for val := range ch {
                    out <- val
                }
            }(v)
        }

    }()
    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}

输出2个核心(go run):

951.0543ms
len= 10000000

输出2个核心(go build):

934.0535ms
len= 10000000

输出8个核心(go run):

575.3447ms
len= 10000000

输出8个核心(go build):

572.3914ms
len= 10000000