所以,我有一段代码是并发的,它应该在每个 CPU/核心上运行。
有两个具有输入/输出值的大向量
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/核心配备一个 worker,每个 worker 处理行的一个子集。
我遇到的问题是这段代码并不比串行代码快。
现在,我使用的是 Go 1.7,所以 runtime.GOMAXPROCS
应该已经设置为 runtime.NumCPU()
,但即使明确设置也不会提高性能。
- 距离只是
(a-b)*(a-b)
; - 计算有点复杂,但应该是可重入的并使用全局数据仅用于读取(并使用
math.Pow
和math.Sqrt
函数); - 没有其他 goroutine 正在运行。
因此,除了访问全局数据(输入/输出)以进行读取之外,没有我所知道的锁/互斥锁(例如,不使用 math/rand
)。
我也用 -race
编译,但什么也没有出现。
我的主机有 4 个虚拟内核,但是当我运行这段代码时,我得到(使用 htop)CPU 使用率达到 102%,但我预计会达到 380% 左右,就像过去其他使用所有虚拟内核的 go 代码一样核心。
我想研究一下,但我不知道运行时如何分配线程和调度 goroutine。
如何调试此类问题? pprof
在这种情况下可以帮助我吗? runtime
包怎么样?
提前致谢
最佳答案
对不起,最后我测量错了。 @JimB 是对的,我有一个小泄漏,但不足以证明这种幅度的放缓是合理的。
我的期望太高:我并发的函数只在程序开始时被调用,因此性能改进很小。
将模式应用到程序的其他部分后,我得到了预期的结果。我错误地评估了哪个部分最重要。
无论如何,我同时学到了很多有趣的东西,所以非常感谢所有试图提供帮助的人!
关于go - 如何检测阻止在 golang 中使用多个内核的原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42377346/