并行这个概念近来很火,.NET 4 中也引入了 TPL(任务并行库) 和 PLinq(并行Linq)来简化并行编程。
于是想体验下,便从最简单的并行求和开始,看看并行的效率如何。
我用的 CPU 是 i3 530 处理器,属于伪四核。想来如果四核并行求和的话,耗时应是非并行的 25% 左右。
于是编码进行验证:
并行求和效率测试
先生成一个满是随机数的数组:
1
2
3
4
|
var random = new Random();
var data = Enumerable.Range(1, 67108864)
.Select(i => (long)random.Next(int.MaxValue))
.ToArray();
|
这个数组比较大,生成大约要 5 秒钟时间。
测试时使用 Stopwatch 类计时:
1
2
3
4
5
6
7
8
9
10
11
12
|
Stopwatch w = new Stopwatch();
//并行
w.Start();
var sum1 = data.AsParallel().Sum();
w.Stop();
Console.WriteLine(w.ElapsedMilliseconds);
//非并行
w.Reset();
w.Start();
var sum2 = data.Sum();
w.Stop();
Console.WriteLine(w.ElapsedMilliseconds);
|
执行多次结果如下(考虑到执行顺序或许会对结果产生影响,后面五次的执行是把非并行求和放在并行求和前面进行测试的):
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
并行 |
385 |
385 |
376 |
409 |
437 |
342 |
419 |
347 |
379 |
342 |
非并行 |
733 |
666 |
668 |
665 |
669 |
673 |
667 |
670 |
669 |
672 |
(单位:毫秒)
平均起来并行求和只用了 57% 的时间,相对于非并行。虽然效率有提高,但离我们最初设想的 25% 差多了。
莫非只用了两个核,不如从任务管理器中查看下 CPU 使用情况。但是单次执行时间不到一秒,时间太短,不易看清,在代码中再加上个循环:
1
2
3
4
|
for (int i = 0; i < 100; i++)
{
var sum = data.AsParallel().Sum();
}
|
执行,则从下图中可以看出,四核已全部用上:
看来应该是并行求和算法的问题了。不如自己改进下。
简单并行求和算法
思路很简单,把数组分成多块,每个 CPU 核心负责一块的求和,最后把每块的和加起来就是了:
1
2
3
4
5
|
var partitionCount = 4; //分块数量
var partitionLength = (data.Count() - 1) / partitionCount + 1; //每块长度
var results = new long[partitionCount]; //声明一个数组,用来保留各块的和
var r = Parallel.For(0, partitionCount, i => results[i] = PartitionSum(data, partitionLength * i, partitionLength));
var sum3 = results.Sum(); //将各块的和加起来
|
PartitionSum 是一个函数,用来计算某一块的和:
1
2
3
4
5
6
7
8
9
|
public static long PartitionSum(long[] source, int start, int length)
{
long result = 0;
int end = start + length;
if (end > source.Length) end = length;
for (int i = start; i < end; i++)
result += source[i];
return result;
}
|
测试时间为:
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
并行改进 |
153 |
161 |
151 |
154 |
152 |
156 |
157 |
153 |
155 |
153 |
(单位:毫秒)
占非并行执行时间的 23%,与我们最初的预计差不多,要好些。
总结
本文的测试虽然比较简单,粗陋,也不权威,但也从一定程度上说明了 .NET 4 的并行求和算法效率不高。
本文仅对 .NET 4 的并行求和进行了测试,只涉及到 .NET 4 中并行的很少一部分。.NET 4 的并行求和算法效率不高并不表示其它部分效率也不高。
后记:真正四核 CPU Xeon E5606 上的测试结果
回复中有朋友提到可能是伪四核 CPU 的原因,于是我找了一台服务器,装有 Xeon E5606,是货真价实的四核处理器。
测试结果如下:
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
非并行 |
858 |
863 |
861 |
859 |
858 |
862 |
863 |
859 |
861 |
859 |
并行 |
250 |
248 |
280 |
248 |
248 |
248 |
249 |
248 |
249 |
249 |
并行改进 |
121 |
121 |
121 |
121 |
121 |
121 |
121 |
121 |
121 |
121 |
(单位:毫秒)
相对非并行,.NET 并行用时约 29%,我的简单改进算法约 14%。
29% 与最初预期的 25% 很接近,看来原因就在伪四核上了。
(责任编辑:admin) |