如何检测阻止在 golang 中使用多个内核的原因?

How to detect what is preventing multiple cores being used in golang?

所以,我有一段代码是并发的,它意味着 运行 到每个 CPU/core。

有两个具有 input/output 值的大向量

var (
    input = make([]float64, rowCount)
    output = make([]float64, rowCount)
)

这些都已填满,我想计算每个输入输出对之间的距离(误差)。作为独立的对,可能的并发版本如下:

var d float64 // Error to be computed
// Setup a worker "for each CPU"
ch := make(chan float64)
nw := runtime.NumCPU()
for w := 0; w < nw; w++ {
    go func(id int) {
         var wd float64
         // eg nw = 4
         // worker0, i = 0, 4, 8, 12...
         // worker1, i = 1, 5, 9, 13...
         // worker2, i = 2, 6, 10, 14...
         // worker3, i = 3, 7, 11, 15...
         for i := id; i < rowCount; i += nw {
             res := compute(input[i])
             wd += distance(res, output[i])
         }
         ch <- wd
    }(w)
}
// Compute total distance
for w := 0; w < nw; w++ {
    d += <-ch
}

想法是每个 CPU/core 有一个工人,每个工人处理行的一个子集。

我遇到的问题是这段代码并不比串行代码快。

现在,我使用的是 Go 1.7,所以 runtime.GOMAXPROCS 应该已经设置为 runtime.NumCPU(),但即使明确设置它也不会提高性能。

因此,除了访问全局数据 (input/output) 进行阅读外,我还没有发现 locks/mutexes(例如,未使用 math/rand)。

我也是用-race编译的,但什么也没有出现。

我的主机有 4 个虚拟核心,但是当我 运行 这段代码时,我得到(使用 htop)CPU 使用率达到 102%,但我预计大约 380%,因为它发生在过去与其他使用所有内核的 go 代码。

我想研究一下,但我不知道 运行time 是如何分配线程和调度 goroutines 的。

如何调试此类问题?在这种情况下 pprof 可以帮助我吗? runtime 包呢?

提前致谢

对不起,最后我测量错了。 @JimB 是对的,我有一个小泄漏,但不足以证明这种幅度的放缓是合理的。

我的期望太高了:我并发的函数只在程序开始时被调用,因此性能提升很小。

将模式应用到程序的其他部分后,我得到了预期的结果。我在评估哪个部分最重要时的错误。

总之,这期间我学到了很多有趣的东西,非常感谢所有试图提供帮助的人!