【问题标题】:Why concurrent code takes more time to execute为什么并发代码需要更多时间来执行
【发布时间】:2015-04-30 09:35:10
【问题描述】:

我有一个名为 linearize 的函数...我正试图加快它的执行速度,但惊讶地发现它变慢了。我是否错过了什么或搞砸了基础知识..

据我了解,事情应该会有所改善..

谢谢,

package main

import (
    "fmt"
    "math"
    "sync"
    "time"
)

var rgb []float64

func linearizeWithWg(v float64, idx int, wg *sync.WaitGroup) {
    defer wg.Done()

    if v <= 0.04045 {
        rgb[idx] = v / 12.92
    } else {
        rgb[idx] = math.Pow((v+0.055)/1.055, 2.4)
    }
}

func linearizeWithGoR(v float64) float64 {
    res := make(chan float64)

    go func(input float64) {
        if input <= 0.04045 {
            res <- input / 12.92
        } else {
            res <- math.Pow((input+0.055)/1.055, 2.4)
        }
    }(v)
    return <-res
}

func linearizeNomal(v float64) float64 {
    if v <= 0.04045 {
        return v / 12.92
    }
    return math.Pow((v+0.055)/1.055, 2.4)
}

func main() {
    start := time.Now()
    const C = 1.0 / 255.0

    //Normal Execution
    for i := 0; i < 100000; i++ {
        linearizeNomal(float64(i) * C * 0.5)
        linearizeNomal(float64(i) * C * 1.5)
        linearizeNomal(float64(i) * C * 4.5)
    }
    elaspsed := time.Since(start)
    fmt.Println(elaspsed)

    //With GoRoutines.. Slow
    start = time.Now()
    for i := 0; i < 100000; i++ {
        linearizeWithGoR(float64(i) * C * 0.5)
        linearizeWithGoR(float64(i) * C * 1.5)
        linearizeWithGoR(float64(i) * C * 2.5)
    }
    elaspsed = time.Since(start)
    fmt.Println(elaspsed)

    //With WaitGroup. Slow

    for i := 0; i < 100000; i++ {
        rgb = make([]float64, 3)
        var wg sync.WaitGroup
        wg.Add(3)
        linearizeWithWg(float64(i)*C*0.5, 0, &wg)
        linearizeWithWg(float64(i)*C*1.5, 1, &wg)
        linearizeWithWg(float64(i)*C*4.5, 2, &wg)
        wg.Wait()
    }
    elaspsed = time.Since(start)
    fmt.Println(elaspsed)

}

【问题讨论】:

  • 确保你的GOMAXPROCS大于1——否则,所有的goroutine将在一个物理线程中顺序执行。
  • 在@Dean Elbaz cmets 之后修改的代码。 play.golang.org/p/QemdM3ElsX
  • 并发不是并行。并发是一种思考代码的方式,而不是“这运行得更快”的同义词。尽管正确执行并发可能有助于使用所有内核。

标签: multithreading concurrency go


【解决方案1】:

所有与并发相关的功能(通道创建、通道发送、goroutine 创建)的开销比您在每个 goroutine 中执行的两条指令要大得多。

此外,您的 goroutine 版本基本上是串行的,因为您生成一个 goroutine 并立即等待其通道的结果。等待组版本类似。

用少量的 goroutine 再试一次,每个 goroutine 执行你的循环的一部分。 @Joker_vD 还可以确保 GOMAXPROCS 大于一。

【讨论】:

    【解决方案2】:

    你的问题是你实际上并没有同时做任何事情。

    在工作组示例中,您需要调用go linearizeWithWg(...)

    在 goroutine 示例中,您启动了一个 goroutine,然后在函数中等待它结束。要同时运行它,您需要一个缓冲的响应通道,并让另一个 goroutine 获取响应

    【讨论】:

    • 感谢您指出最大的错误...我确实纠正了这一点,我再次看到使用 *wg 执行它没有什么重大好处这里是一些快速统计...正常执行需要.. 38.ms 和 wg 的修改代码需要 1.82s 现在我还添加了代码 nCPU := runtime.NumCPU() runtime.GOMAXPROCS(nCPU) @inf 建议的开销吗?
    • 是的,开销是可能的。如果有很多上下文切换来回成本。如果并行例程每个都执行更大、长时间运行的计算/处理,则并行运行更有意义。小块处理,然后需要同步另一个线程可能会非常慢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-10
    • 2018-01-28
    • 2020-08-28
    • 2017-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多