并发代码为什么需要更长的执行时间?

huangapple go评论92阅读模式
英文:

Why concurrent code takes more time to execute

问题

我有一个名为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

	//正常执行
	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)

	//使用Go协程...慢
	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)

	//使用WaitGroup。慢

	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)

}
英文:

I have a function named linearize...I'm trying to speed up its execution but surprised to find that it had become slower. Have I missed something or have messed up with fundamentals..

As per my understanding things should improve..

Thanks,

package main
import (
&quot;fmt&quot;
&quot;math&quot;
&quot;sync&quot;
&quot;time&quot;
)
var rgb []float64
func linearizeWithWg(v float64, idx int, wg *sync.WaitGroup) {
defer wg.Done()
if v &lt;= 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 &lt;= 0.04045 {
res &lt;- input / 12.92
} else {
res &lt;- math.Pow((input+0.055)/1.055, 2.4)
}
}(v)
return &lt;-res
}
func linearizeNomal(v float64) float64 {
if v &lt;= 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 &lt; 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 &lt; 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 &lt; 100000; i++ {
rgb = make([]float64, 3)
var wg sync.WaitGroup
wg.Add(3)
linearizeWithWg(float64(i)*C*0.5, 0, &amp;wg)
linearizeWithWg(float64(i)*C*1.5, 1, &amp;wg)
linearizeWithWg(float64(i)*C*4.5, 2, &amp;wg)
wg.Wait()
}
elaspsed = time.Since(start)
fmt.Println(elaspsed)
}

答案1

得分: 8

所有与并发相关的函数(通道创建、通道发送、goroutine创建)的开销远远大于每个goroutine中执行的两条指令。

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

尝试使用少量的goroutine,每个goroutine执行循环的一个块。@Joker_vD还提到确保GOMAXPROCS大于1。

英文:

The overhead of all the concurrency related functions(channel creation, channel sending, goroutine creation) is way bigger than the two instructions that you execute in each of your goroutine.

In addition, your goroutine version is basically serial because you spawn a goroutine and immediately wait for the result of its channel. The waitgroup version is similar.

Try again with a small number of goroutines each executing a chunk of your loop. @Joker_vD also has a good point to make sure that GOMAXPROCS is bigger than one.

答案2

得分: 3

你的问题是你实际上没有并发执行任何操作。

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

在 goroutine 示例中,你启动了一个 goroutine,但是在函数中等待它结束。要并发运行它,你需要一个带缓冲的响应通道,并且有另一个 goroutine 获取响应。

英文:

Your problem is that you don't actually do anything concurrently.

in the workgroup example, you need to call go linearizeWithWg(...)

In the goroutine example, you start a goroutine, but then wait for it to end in the function. To run it concurrently, you would need a buffered response channel, and having another goroutine getting the responses

huangapple
  • 本文由 发表于 2015年4月30日 17:35:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/29964104.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定