并行.为了性能
本文关键字:性能 并行 | 更新日期: 2023-09-27 18:27:30
此代码来自Microsoft文章http://msdn.microsoft.com/en-us/library/dd460703.aspx,有小改动:
const int size = 10000000;
int[] nums = new int[size];
Parallel.For(0, size, i => {nums[i] = 1;});
long total = 0;
Parallel.For<long>(
0, size, () => 0,
(j, loop, subtotal) =>
{
return subtotal + nums[j];
},
(x) => Interlocked.Add(ref total, x)
);
if (total != size)
{
Console.WriteLine("Error");
}
非并行循环版本为:
for (int i = 0; i < size; ++i)
{
total += nums[i];
}
当我使用StopWatch
类测量循环执行时间时,我发现并行版本慢了10-20%。测试是在Windows 7 64位、英特尔i5-2400 CPU、4核、4GB RAM上完成的。当然,在Release配置中。
在我的实际程序中,我试图计算一个图像直方图,并行版本的运行速度慢了10倍。当每次循环调用都很快时,这种计算任务能否成功地与TPL并行?
编辑
最后,我设法用Parallel减少了50%以上的直方图计算执行时间。例如,当将整个图像分割成一定数量的块时。现在,每个循环体调用都处理整个块,而不是一个像素。
因为Parallel.For
应该用于有点健康的事情,而不是简单的数字求和!仅仅使用委托(j, loop, subtotal) =>
可能就足以多给10-20%的时间。我们甚至没有谈到线程开销。如果能在for周期中看到一些针对代表夏季的基准,并且不仅能看到"真实世界"时间,还能看到CPU时间,那将是一件有趣的事情。
我甚至添加了一个与"简单"委托的比较,该委托的作用与Parallel.For<>
委托相同。
嗯。。。现在我有一些32位的数字,在我的电脑上(AMD六核)
32 bits
Parallel: Ticks: 74581, Total ProcessTime: 2496016
Base : Ticks: 90395, Total ProcessTime: 312002
Func : Ticks: 147037, Total ProcessTime: 468003
Parallel在墙时间稍微快一点,但在处理器时间慢8倍:-)
但在64位:
64 bits
Parallel: Ticks: 104326, Total ProcessTime: 2652017
Base : Ticks: 51664, Total ProcessTime: 156001
Func : Ticks: 77861, Total ProcessTime: 312002
修改代码:
Console.WriteLine("{0} bits", IntPtr.Size == 4 ? 32 : 64);
var cp = Process.GetCurrentProcess();
cp.PriorityClass = ProcessPriorityClass.High;
const int size = 10000000;
int[] nums = new int[size];
Parallel.For(0, size, i => { nums[i] = 1; });
GC.Collect();
GC.WaitForPendingFinalizers();
long total = 0;
{
TimeSpan start = cp.TotalProcessorTime;
Stopwatch sw = Stopwatch.StartNew();
Parallel.For<long>(
0, size, () => 0,
(j, loop, subtotal) =>
{
return subtotal + nums[j];
},
(x) => Interlocked.Add(ref total, x)
);
sw.Stop();
TimeSpan end = cp.TotalProcessorTime;
Console.WriteLine("Parallel: Ticks: {0,10}, Total ProcessTime: {1,10}", sw.ElapsedTicks, (end - start).Ticks);
}
if (total != size)
{
Console.WriteLine("Error");
}
GC.Collect();
GC.WaitForPendingFinalizers();
total = 0;
{
TimeSpan start = cp.TotalProcessorTime;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < size; ++i)
{
total += nums[i];
}
sw.Stop();
TimeSpan end = cp.TotalProcessorTime;
Console.WriteLine("Base : Ticks: {0,10}, Total ProcessTime: {1,10}", sw.ElapsedTicks, (end - start).Ticks);
}
if (total != size)
{
Console.WriteLine("Error");
}
GC.Collect();
GC.WaitForPendingFinalizers();
total = 0;
Func<int, int, long, long> adder = (j, loop, subtotal) =>
{
return subtotal + nums[j];
};
{
TimeSpan start = cp.TotalProcessorTime;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < size; ++i)
{
total = adder(i, 0, total);
}
sw.Stop();
TimeSpan end = cp.TotalProcessorTime;
Console.WriteLine("Func : Ticks: {0,10}, Total ProcessTime: {1,10}", sw.ElapsedTicks, (end - start).Ticks);
}
if (total != size)
{
Console.WriteLine("Error");
}