并发对象的创建会显著降低执行时间。

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

Creation of concurrency objects dramatically slows down execution time

问题

我已经得到这段代码,并被要求找出如何使用并发来加速处理过程。

如果我运行这段代码,我会得到以下输出:

  1. Elapsed time (us) = 26546

然后我用Go语言编写了一个类似的程序:

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "time"
  6. )
  7. const size int64 = 10000000
  8. var (
  9. a = [size]float32{}
  10. b = [size]float32{}
  11. )
  12. func main() {
  13. var (
  14. i int64
  15. sum float32
  16. time1 time.Time
  17. time2 time.Time
  18. )
  19. rand.Seed(time.Now().UnixNano())
  20. for i = 0; i < size; i++ {
  21. a[i] = rand.Float32()
  22. b[i] = rand.Float32()
  23. }
  24. time1 = time.Now() //Original place
  25. sum = 0.0
  26. for i = 0; i < size; i++ {
  27. sum = sum + a[i] + b[i]
  28. }
  29. time2 = time.Now()
  30. fmt.Printf("Elapsed time (us) = %d\n", time2.Sub(time1).Microseconds())
  31. }

我得到了这个输出(非常令人惊讶地比C版本更快):

  1. Elapsed time (us) = 2462

我的任务是尝试使用并发使其更快,我想到可以通过并行运行数组的创建来加速它们,但是计时器只在创建之后启动。所以我不知道如何加速它,因为值需要合并,这将是一个顺序过程。

所以我将启动计时器移到创建时间之前,得到C程序的结果如下:

  1. Elapsed time (us) = 172496

Go程序的结果如下:

  1. Elapsed time (us) = 247603

所以现在Go比C慢,这是预期的。

然后我尝试将Go程序更改为在每个goroutine中创建每个数组:

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "sync"
  6. "time"
  7. )
  8. const size int = 10000000
  9. var (
  10. a = [size]float64{}
  11. b = [size]float64{}
  12. )
  13. func main() {
  14. var (
  15. wg sync.WaitGroup
  16. sum float64
  17. time1 time.Time
  18. time2 time.Time
  19. )
  20. rand.Seed(time.Now().UnixNano())
  21. wg.Add(2)
  22. time1 = time.Now()
  23. go func() {
  24. for i := 0; i < size; i++ {
  25. a[i] = rand.Float64()
  26. }
  27. wg.Done()
  28. }()
  29. go func() {
  30. for i := 0; i < size; i++ {
  31. b[i] = rand.Float64()
  32. }
  33. wg.Done()
  34. }()
  35. wg.Wait()
  36. sum = 0.0
  37. for i := 0; i < size; i++ {
  38. sum = sum + a[i] + b[i]
  39. }
  40. time2 = time.Now()
  41. fmt.Printf("Elapsed time (us) = %d\n", time2.Sub(time1).Microseconds())
  42. }

我得到了以下输出:

  1. Elapsed time (us) = 395808

这相当慢,我认为这与函数的调用和等待组逻辑有关。

然后我尝试使用通道。

这只会使程序运行很长时间,并且代码非常冗长。

然后我尝试让每个goroutine自己添加字段:

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "sync"
  6. "time"
  7. )
  8. const size int = 10000000
  9. func main() {
  10. var (
  11. wg sync.WaitGroup
  12. sum float64
  13. asum float64
  14. bsum float64
  15. time1 time.Time
  16. time2 time.Time
  17. )
  18. rand.Seed(time.Now().UnixNano())
  19. wg.Add(2)
  20. time1 = time.Now()
  21. go func() {
  22. asum = 0
  23. for i := 0; i < size; i++ {
  24. asum = asum + rand.Float64()
  25. }
  26. wg.Done()
  27. }()
  28. go func() {
  29. bsum = 0
  30. for i := 0; i < size; i++ {
  31. bsum = bsum + rand.Float64()
  32. }
  33. wg.Done()
  34. }()
  35. wg.Wait()
  36. sum = asum + bsum
  37. time2 = time.Now()
  38. fmt.Printf("Elapsed time (us) = %d\n", time2.Sub(time1).Microseconds())
  39. fmt.Println(sum)
  40. }

它返回了以下结果:

  1. Elapsed time (us) = 395182
  2. 1.000137482475232e+07

我必须使用sum变量才能运行程序-这就是为什么我打印它。

所以我似乎无法通过并发使这个程序运行得更快。

有人对此有什么提示吗?或者我应该在并发产生效果之前运行更多的任务?这只是因为我在这种情况下只处理了2个任务,并且数组处理速度非常快吗?

英文:

I have gotten this code and been asked to find out how I can use concurrency to speed up the process.

  1. #include &lt;stdio.h&gt;
  2. #include &lt;stdlib.h&gt;
  3. #include &lt;time.h&gt;
  4. #include &lt;sys/time.h&gt;
  5. #define SIZE 10000000
  6. volatile float a[SIZE];
  7. volatile float b[SIZE];
  8. int main(int argc, char **argv)
  9. {
  10. long int i;
  11. double sum;
  12. struct timeval time1, time2;
  13. srand(time(0));
  14. for (i = 0; i &lt; SIZE; i++)
  15. {
  16. a[i] = rand();
  17. b[i] = rand();
  18. }
  19. gettimeofday(&amp;time1, 0); //Original place
  20. sum = 0.0;
  21. for (i = 0; i &lt; SIZE; i++)
  22. {
  23. sum = sum + a[i]*b[i];
  24. }
  25. gettimeofday(&amp;time2, 0);
  26. printf(&quot;Elapsed time (us) = %d\n&quot;, (time2.tv_sec-time1.tv_sec)*1000000 + time2.tv_usec - time1.tv_usec);
  27. return 0;
  28. }

if I run the code I get the output

  1. Elapsed time (us) = 26546

Then I wrote a similar program in Go

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;math/rand&quot;
  5. &quot;time&quot;
  6. )
  7. const size int64 = 10000000
  8. var (
  9. a = [size]float32{}
  10. b = [size]float32{}
  11. )
  12. func main() {
  13. var (
  14. i int64
  15. sum float32
  16. time1 time.Time
  17. time2 time.Time
  18. )
  19. rand.Seed(time.Now().UnixNano())
  20. for i = 0; i &lt; size; i++ {
  21. a[i] = rand.Float32()
  22. b[i] = rand.Float32()
  23. }
  24. time1 = time.Now() //Original place
  25. sum = 0.0
  26. for i = 0; i &lt; size; i++ {
  27. sum = sum + a[i] + b[i]
  28. }
  29. time2 = time.Now()
  30. fmt.Printf(&quot;Elapsed time (us) = %d\n&quot;, time2.Sub(time1).Microseconds())
  31. }

An I get this output (which was very surprisingly faster than the C version)

  1. Elapsed time (us) = 2462

My job was to try to make it faster with concurrency, and I was thinking that the creation of the arrays could be speed up if they would be run in parallel, However the timer is only started after the creation. So then I don't really know how I can speed it up since the values need to be merges which would be a sequential process.

So I move the start timer over the creation time and get for the c program:

  1. Elapsed time (us) = 172496

and for the go program:

  1. Elapsed time (us) = 247603

So now go is slower than C as expected.

Then I tried to change my go program to create each array in its own goroutine:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;math/rand&quot;
  5. &quot;sync&quot;
  6. &quot;time&quot;
  7. )
  8. const size int = 10000000
  9. var (
  10. a = [size]float64{}
  11. b = [size]float64{}
  12. )
  13. func main() {
  14. var (
  15. wg sync.WaitGroup
  16. sum float64
  17. time1 time.Time
  18. time2 time.Time
  19. )
  20. rand.Seed(time.Now().UnixNano())
  21. wg.Add(2)
  22. time1 = time.Now()
  23. go func() {
  24. for i := 0; i &lt; size; i++ {
  25. a[i] = rand.Float64()
  26. }
  27. wg.Done()
  28. }()
  29. go func() {
  30. for i := 0; i &lt; size; i++ {
  31. b[i] = rand.Float64()
  32. }
  33. wg.Done()
  34. }()
  35. wg.Wait()
  36. sum = 0.0
  37. for i := 0; i &lt; size; i++ {
  38. sum = sum + a[i] + b[i]
  39. }
  40. time2 = time.Now()
  41. fmt.Printf(&quot;Elapsed time (us) = %d\n&quot;, time2.Sub(time1).Microseconds())
  42. }

and I get the output:

  1. Elapsed time (us) = 395808

Which is quite slow. and I expect that this has something to do with the invokation of the functions and the waitgroup logic.

Then I tried with channels.

Which just made the program take forever, and the code waay to long.

Then I tried with each coroutine adding the fields itself

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;math/rand&quot;
  5. &quot;sync&quot;
  6. &quot;time&quot;
  7. )
  8. const size int = 10000000
  9. func main() {
  10. var (
  11. wg sync.WaitGroup
  12. sum float64
  13. asum float64
  14. bsum float64
  15. time1 time.Time
  16. time2 time.Time
  17. )
  18. rand.Seed(time.Now().UnixNano())
  19. wg.Add(2)
  20. time1 = time.Now()
  21. go func() {
  22. asum = 0
  23. for i := 0; i &lt; size; i++ {
  24. asum = asum + rand.Float64()
  25. }
  26. wg.Done()
  27. }()
  28. go func() {
  29. bsum = 0
  30. for i := 0; i &lt; size; i++ {
  31. bsum = bsum + rand.Float64()
  32. }
  33. wg.Done()
  34. }()
  35. wg.Wait()
  36. sum = asum + bsum
  37. time2 = time.Now()
  38. fmt.Printf(&quot;Elapsed time (us) = %d\n&quot;, time2.Sub(time1).Microseconds())
  39. fmt.Println(sum)
  40. }

which returned

  1. Elapsed time (us) = 395182
  2. 1.000137482475232e+07

I had to use the sum as well to be able to run the program - thats why I print it.


So I just cant seem to get this program to run any faster with concurrency.

Does anyone have a hint for me? or should I just run more jobs before concurrency will have any effect? Is it just because I only deal with 2 jobs in this case, and because arrays are so fast to process?

答案1

得分: 2

并发可以加快执行时间。

Go程序:

经过的时间(微秒)= 130768

带有并发的Go程序:

经过的时间(微秒)= 66947

为了使每个goroutine都拥有自己的rand.Rand实例,请使用rand.New(src Source)。


运行C程序的Go版本。

x.go

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "time"
  6. )
  7. const size = 10000000
  8. var (
  9. a = [size]float32{}
  10. b = [size]float32{}
  11. )
  12. func main() {
  13. start := time.Now()
  14. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  15. for i := 0; i < size; i++ {
  16. a[i] = r.Float32()
  17. b[i] = r.Float32()
  18. }
  19. sum := 0.0
  20. for i := 0; i < size; i++ {
  21. sum += float64(a[i]) * float64(b[i])
  22. }
  23. since := time.Since(start).Microseconds()
  24. fmt.Printf("经过的时间(微秒)= %d\n", since)
  25. }

.

  1. $ go build x.go && ./x
  2. 经过的时间(微秒)= 130768
  3. $

运行并发的Go版本的C程序。

y.go

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "sync"
  6. "time"
  7. )
  8. const size = 10000000
  9. var (
  10. a = [size]float32{}
  11. b = [size]float32{}
  12. )
  13. func main() {
  14. start := time.Now()
  15. var wg sync.WaitGroup
  16. wg.Add(2)
  17. go func() {
  18. defer wg.Done()
  19. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  20. for i := 0; i < size; i++ {
  21. a[i] = r.Float32()
  22. }
  23. }()
  24. go func() {
  25. defer wg.Done()
  26. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  27. for i := 0; i < size; i++ {
  28. b[i] = r.Float32()
  29. }
  30. }()
  31. wg.Wait()
  32. sum := 0.0
  33. for i := 0; i < size; i++ {
  34. sum += float64(a[i]) * float64(b[i])
  35. }
  36. since := time.Since(start).Microseconds()
  37. fmt.Printf("经过的时间(微秒)= %d\n", since)
  38. }

.

  1. $ go build y.go && ./y
  2. 经过的时间(微秒)= 66947
  3. $
英文:

Concurrency speeds up execution time.

Go program:

Elapsed time (us) = 130768

Go program with concurrency:

Elapsed time (us) = 66947

For each goroutine to have its own rand.Rand instance, use rand.New(src Source).


Run a Go version of the C program.

x.go:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;math/rand&quot;
  5. &quot;time&quot;
  6. )
  7. const size = 10000000
  8. var (
  9. a = [size]float32{}
  10. b = [size]float32{}
  11. )
  12. func main() {
  13. start := time.Now()
  14. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  15. for i := 0; i &lt; size; i++ {
  16. a[i] = r.Float32()
  17. b[i] = r.Float32()
  18. }
  19. sum := 0.0
  20. for i := 0; i &lt; size; i++ {
  21. sum += float64(a[i]) * float64(b[i])
  22. }
  23. since := time.Since(start).Microseconds()
  24. fmt.Printf(&quot;Elapsed time (us) = %d\n&quot;, since)
  25. }

.

  1. $ go build x.go &amp;&amp; ./x
  2. Elapsed time (us) = 130768
  3. $

Run a concurrent Go version of the C program.

y.go:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;math/rand&quot;
  5. &quot;sync&quot;
  6. &quot;time&quot;
  7. )
  8. const size = 10000000
  9. var (
  10. a = [size]float32{}
  11. b = [size]float32{}
  12. )
  13. func main() {
  14. start := time.Now()
  15. var wg sync.WaitGroup
  16. wg.Add(2)
  17. go func() {
  18. defer wg.Done()
  19. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  20. for i := 0; i &lt; size; i++ {
  21. a[i] = r.Float32()
  22. }
  23. }()
  24. go func() {
  25. defer wg.Done()
  26. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  27. for i := 0; i &lt; size; i++ {
  28. b[i] = r.Float32()
  29. }
  30. }()
  31. wg.Wait()
  32. sum := 0.0
  33. for i := 0; i &lt; size; i++ {
  34. sum += float64(a[i]) * float64(b[i])
  35. }
  36. since := time.Since(start).Microseconds()
  37. fmt.Printf(&quot;Elapsed time (us) = %d\n&quot;, since)
  38. }

.

  1. $ go build y.go &amp;&amp; ./y
  2. Elapsed time (us) = 66947
  3. $

huangapple
  • 本文由 发表于 2021年12月22日 10:16:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/70443550.html
匿名

发表评论

匿名网友

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

确定