Go-lang并行段运行速度比串行段慢

标签 go concurrency parallel-processing

我已经建立了一个流行的数学模型,它在围棋中的计算量相当大。我现在正在尝试构建一组系统来测试我的模型,我在其中更改输入并期望得到不同的输出。我构建了一个系列版本来缓慢增加 HIV 流行率并查看对 HIV 死亡的影响。运行大约需要 200 毫秒。

for q = 0.0; q < 1000; q++ {

    inputs.CountryProfile.HivPrevalenceAdultsByGroup[0] = inputs.CountryProfile.HivPrevalenceAdultsByGroup[0] * float32(math.Pow(1.00001, q))
    results := costAnalysisHandler(inputs)
    fmt.Println(results.HivDeaths[20])

}

然后我使用 channel 制作了一个“并行”版本,它需要更长,~400 毫秒来运行。这些小的变化很重要,因为我们将使用不同的输入运行数百万次运行,因此希望使其尽可能高效。这是并行版本:

ch := make(chan ChData)
var q float64
for q = 0.0; q < 1000; q++ {
    go func(q float64, inputs *costanalysis.Inputs, ch chan ChData) {
        inputs.CountryProfile.HivPrevalenceAdultsByGroup[0] = inputs.CountryProfile.HivPrevalenceAdultsByGroup[0] * float32(math.Pow(1.00001, q))
        results := costAnalysisHandler(inputs)
        fmt.Println(results.HivDeaths[20])
        ch <- ChData{int(q), results.HivDeaths[20]}
    }(q, inputs, ch)
}
for q = 0.0; q < 1000; q++ {
    theResults := <-ch
    fmt.Println(theResults)
}

任何想法都非常感谢

最佳答案

启动后台任务并与之通信会产生开销。如果程序花费 200 毫秒,花在成本分析上的时间可能会相形见绌 等于通信成本,但如果协调成本确实杀死了你的应用程序,一个常见的方法是一次交接大量工作——例如,让每个 goroutine 对 10 个 q 值的范围进行分析,而不仅仅是一个。 (编辑:正如@Innominate 所说,制作一个处理作业对象队列的 goroutines 的“工作池”是另一种常见的方法。)

此外,您粘贴的代码存在竞争条件。 Inputs 结构的内容不会在每次生成 goroutine 时都被复制,因为您正在向函数传递一个指针。因此,并行运行的 goroutines 将读取和写入相同的 Inputs 实例。

只需为每个分析制作一个全新的 Inputs 实例,使用它自己的数组等,就可以避免竞争。如果最终浪费大量内存或导致大量冗余副本,您可以 1) recycle Inputs instances , 2) 分离出可以安全共享的只读数据(也许有固定的国家/地区数据,不知道),或 3) 将一些相对较大的数组更改为 costAnalysisHandler 中的局部变量,而不是需要传递的东西(也许它可以只采用初始 HIV 流行率并在 t=20 时返回 HIV 死亡,其他一切都是本地的并且在堆栈上)。

这不适用于今天的 Go,但在最初发布问题时适用:除非您以所需的并发级别调用 runtime.GOMAXPROCS(),否则没有什么是真正并行运行的,例如, runtime.GOMAXPROCS(runtime.NumCPU())

最后,只有在进行更大规模的分析并且确实存在性能问题时,您才应该担心所有这些问题;如果 0.2 秒的等待是性能工作可以为您节省的全部时间,那是不值得的。

关于Go-lang并行段运行速度比串行段慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20670242/

相关文章:

java - Java线程池服务器: I am only able to either read the request,或成功发送响应,但不能同时发送响应

c# - 跨进程互斥体实例化

c++ - OpenMP - Easy Loop,但仍然是无限的?

c - 二维数组错误: Subscripted value is neither array nor pointer nor vector

go - 在 go 中从外部包扩展一个流畅的 API

go - 如何处理 stderr?

go - 是否可以在 go 插件和应用程序之间共享自定义数据类型?

go - Rethinkdb如何使用唯一键进行选择

Java 线程 : Figure out which threads are still running

java - java中的并行矩阵乘法