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

标签 go concurrency goroutine

所以,我有一段代码是并发的,它应该在每个 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.Powmath.Sqrt 函数);
  • 没有其他 goroutine 正在运行。

因此,除了访问全局数据(输入/输出)以进行读取之外,没有我所知道的锁/互斥锁(例如,不使用 math/rand)。

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

我的主机有 4 个虚拟内核,但是当我运行这段代码时,我得到(使用 htop)CPU 使用率达到 102%,但我预计会达到 380% 左右,就像过去其他使用所有虚拟内核的 go 代码一样核心。

我想研究一下,但我不知道运行时如何分配线程和调度 goroutine。

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

提前致谢

最佳答案

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

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

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

无论如何,我同时学到了很多有趣的东西,所以非常感谢所有试图提供帮助的人!

关于go - 如何检测阻止在 golang 中使用多个内核的原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42377346/

相关文章:

Goroutine并行执行确认

time - 在 golang TCP 中禁用截止日期

xml - 根据 Go 中的 XML 模式验证 XML 文档

java - stub 的 gRPC 并发

go - 读取子进程的 stdout 和 stderr 的竞争条件

go - 像 erlang spawn 这样的 goroutine 可以跨多个主机透明地处理吗?

random - 在最小值、最大值之间生成加密随机整数

time - Go time.Format 错误的月份

python - psycopg2.ThreadConnectionPool、uWSGI 和 Flask 的并发问题

java - 使用 System.out.print 按顺序打印 RED BLUE GREEN