如何检测阻止在 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()
,但即使明确设置它也不会提高性能。
- 距离刚好
(a-b)*(a-b)
;
- 计算有点复杂,但应该是可重入的并且使用全局数据仅用于读取(并使用
math.Pow
和math.Sqrt
函数);
- 没有其他 goroutine 是 运行ning。
因此,除了访问全局数据 (input/output) 进行阅读外,我还没有发现 locks/mutexes(例如,未使用 math/rand
)。
我也是用-race
编译的,但什么也没有出现。
我的主机有 4 个虚拟核心,但是当我 运行 这段代码时,我得到(使用 htop)CPU 使用率达到 102%,但我预计大约 380%,因为它发生在过去与其他使用所有内核的 go 代码。
我想研究一下,但我不知道 运行time 是如何分配线程和调度 goroutines 的。
如何调试此类问题?在这种情况下 pprof
可以帮助我吗? runtime
包呢?
提前致谢
对不起,最后我测量错了。 @JimB 是对的,我有一个小泄漏,但不足以证明这种幅度的放缓是合理的。
我的期望太高了:我并发的函数只在程序开始时被调用,因此性能提升很小。
将模式应用到程序的其他部分后,我得到了预期的结果。我在评估哪个部分最重要时的错误。
总之,这期间我学到了很多有趣的东西,非常感谢所有试图提供帮助的人!
所以,我有一段代码是并发的,它意味着 运行 到每个 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()
,但即使明确设置它也不会提高性能。
- 距离刚好
(a-b)*(a-b)
; - 计算有点复杂,但应该是可重入的并且使用全局数据仅用于读取(并使用
math.Pow
和math.Sqrt
函数); - 没有其他 goroutine 是 运行ning。
因此,除了访问全局数据 (input/output) 进行阅读外,我还没有发现 locks/mutexes(例如,未使用 math/rand
)。
我也是用-race
编译的,但什么也没有出现。
我的主机有 4 个虚拟核心,但是当我 运行 这段代码时,我得到(使用 htop)CPU 使用率达到 102%,但我预计大约 380%,因为它发生在过去与其他使用所有内核的 go 代码。
我想研究一下,但我不知道 运行time 是如何分配线程和调度 goroutines 的。
如何调试此类问题?在这种情况下 pprof
可以帮助我吗? runtime
包呢?
提前致谢
对不起,最后我测量错了。 @JimB 是对的,我有一个小泄漏,但不足以证明这种幅度的放缓是合理的。
我的期望太高了:我并发的函数只在程序开始时被调用,因此性能提升很小。
将模式应用到程序的其他部分后,我得到了预期的结果。我在评估哪个部分最重要时的错误。
总之,这期间我学到了很多有趣的东西,非常感谢所有试图提供帮助的人!