【发布时间】:2022-01-23 08:28:33
【问题描述】:
我已获得此代码,并被要求了解如何使用并发来加快处理速度。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#define SIZE 10000000
volatile float a[SIZE];
volatile float b[SIZE];
int main(int argc, char **argv)
{
long int i;
double sum;
struct timeval time1, time2;
srand(time(0));
for (i = 0; i < SIZE; i++)
{
a[i] = rand();
b[i] = rand();
}
gettimeofday(&time1, 0); //Original place
sum = 0.0;
for (i = 0; i < SIZE; i++)
{
sum = sum + a[i]*b[i];
}
gettimeofday(&time2, 0);
printf("Elapsed time (us) = %d\n", (time2.tv_sec-time1.tv_sec)*1000000 + time2.tv_usec - time1.tv_usec);
return 0;
}
如果我运行代码,我会得到输出
Elapsed time (us) = 26546
然后我用 Go 写了一个类似的程序
package main
import (
"fmt"
"math/rand"
"time"
)
const size int64 = 10000000
var (
a = [size]float32{}
b = [size]float32{}
)
func main() {
var (
i int64
sum float32
time1 time.Time
time2 time.Time
)
rand.Seed(time.Now().UnixNano())
for i = 0; i < size; i++ {
a[i] = rand.Float32()
b[i] = rand.Float32()
}
time1 = time.Now() //Original place
sum = 0.0
for i = 0; i < size; i++ {
sum = sum + a[i] + b[i]
}
time2 = time.Now()
fmt.Printf("Elapsed time (us) = %d\n", time2.Sub(time1).Microseconds())
}
我得到了这个输出(这比 C 版本快得多)
Elapsed time (us) = 2462
我的工作是尝试通过并发使其更快,并且我认为如果它们并行运行可以加快数组的创建速度,但是计时器仅在创建后启动。所以我真的不知道如何加快速度,因为值需要合并,这将是一个顺序过程。
所以我将启动计时器移到创建时间上并获取 c 程序:
Elapsed time (us) = 172496
对于 go 程序:
Elapsed time (us) = 247603
所以现在 go 比预期的慢。
然后我尝试更改我的 go 程序以在其自己的 goroutine 中创建每个数组:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
const size int = 10000000
var (
a = [size]float64{}
b = [size]float64{}
)
func main() {
var (
wg sync.WaitGroup
sum float64
time1 time.Time
time2 time.Time
)
rand.Seed(time.Now().UnixNano())
wg.Add(2)
time1 = time.Now()
go func() {
for i := 0; i < size; i++ {
a[i] = rand.Float64()
}
wg.Done()
}()
go func() {
for i := 0; i < size; i++ {
b[i] = rand.Float64()
}
wg.Done()
}()
wg.Wait()
sum = 0.0
for i := 0; i < size; i++ {
sum = sum + a[i] + b[i]
}
time2 = time.Now()
fmt.Printf("Elapsed time (us) = %d\n", time2.Sub(time1).Microseconds())
}
我得到了输出:
Elapsed time (us) = 395808
这很慢。我希望这与函数的调用和等待组逻辑有关。
然后我尝试使用频道。
这只是让程序永远耗时,而且代码也很长。
然后我尝试使用每个协程自己添加字段
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
const size int = 10000000
func main() {
var (
wg sync.WaitGroup
sum float64
asum float64
bsum float64
time1 time.Time
time2 time.Time
)
rand.Seed(time.Now().UnixNano())
wg.Add(2)
time1 = time.Now()
go func() {
asum = 0
for i := 0; i < size; i++ {
asum = asum + rand.Float64()
}
wg.Done()
}()
go func() {
bsum = 0
for i := 0; i < size; i++ {
bsum = bsum + rand.Float64()
}
wg.Done()
}()
wg.Wait()
sum = asum + bsum
time2 = time.Now()
fmt.Printf("Elapsed time (us) = %d\n", time2.Sub(time1).Microseconds())
fmt.Println(sum)
}
返回的
Elapsed time (us) = 395182
1.000137482475232e+07
我还必须使用总和才能运行程序 - 这就是我打印它的原因。
所以我似乎无法让这个程序在并发的情况下运行得更快。
有人给我提示吗?或者我应该在并发产生任何影响之前运行更多的工作?是不是因为在这种情况下我只处理了 2 个作业,并且因为数组的处理速度如此之快?
【问题讨论】:
-
在 C 代码中,
a[i]与b[i]相乘,而在 Go 代码中,a[i]与b[i]相乘。这似乎不是一个公平的比较。 -
使用
volatile可能会阻止某些编译器优化。如果您想确保您的计算具有可观察到的效果,以便编译器无法优化计算,那么您可能只想简单地打印sum。 -
在对程序进行基准测试时,准确了解您如何编译它们会很有用,这样我们就可以了解您正在应用的编译器优化级别。
-
删除
a和b数组中的“volatile”限定符。它的存在削弱了几乎所有可能的优化。 -
@AndreasWenzel 哇,我完全错过了。
标签: c go concurrency