普通计算,线程池,并行技术的速度对比
.NET 4.0中引入了 TPL(任务并行库),关于TPL,MSDN的简介是:
任务并行库 (TPL) 的设计是为了能更简单地编写可自动使用多处理器的托管代码。使用该库,您可以非常方便地用现有序列代码表达潜在并行性,这样序列代码中公开的并行任务将会在所有可用的处理器上同时运行。通常这会大大提高速度。
以前对于可能出现性能的地方都是使用线程池,最近在项目中尝试使用 TPL, 下面是我的测试代码,测试普通计算,线程池,和 TPL 的运算速度对比
public class Program { private static int[] results; private static AutoResetEvent[] rets; public static void Main() { Stopwatch sw = new Stopwatch(); int count = 10; results = new int[count]; Console.WriteLine("顺序计算开始"); sw.Start(); for (int i = 0; i < count; i++) { results[i] = CalculateA(i); } sw.Stop(); Console.WriteLine("顺序计算,总耗时{0}", sw.ElapsedTicks); Console.WriteLine("Result:{0}", results[0] + "#" + results[1] + "#" + results[2] + "#" + results[3] + "#" + results[4] + "#" + results[5] + "#" + results[6] + "#" + results[7] + "#" + results[8] + "#" + results[9]); Console.WriteLine("使用线程池计算开始1"); sw.Restart(); rets = new AutoResetEvent[count]; //初始化 autoresetevent for (int i = 0; i < count; i++) { rets[i] = new AutoResetEvent(false); } for (int i = 0; i < count; i++) { WaitCallback wait = new WaitCallback(CalculateB); ThreadPool.QueueUserWorkItem(wait, i); } WaitHandle.WaitAll(rets); Console.WriteLine("使用线程池计算1,总耗时{0}", sw.ElapsedTicks); Console.WriteLine("Result:{0}", results[0] + "#" + results[1] + "#" + results[2] + "#" + results[3] + "#" + results[4] + "#" + results[5] + "#" + results[6] + "#" + results[7] + "#" + results[8] + "#" + results[9]); //由于默认线程池中有两个线程,第一次调用线程池计算,由于有任务排队,系统会每半秒钟添加新的线程进入线程池,所以理论上第二次比第一次执行时间会短 Console.WriteLine("使用线程池计算开始2"); sw.Restart(); for (int i = 0; i < count; i++) { WaitCallback wait = new WaitCallback(CalculateB); ThreadPool.QueueUserWorkItem(wait, i); } WaitHandle.WaitAll(rets); Console.WriteLine("使用线程池计算2,总耗时{0}", sw.ElapsedTicks); Console.WriteLine("Result:{0}", results[0] + "#" + results[1] + "#" + results[2] + "#" + results[3] + "#" + results[4] + "#" + results[5] + "#" + results[6] + "#" + results[7] + "#" + results[8] + "#" + results[9]); Console.WriteLine("并行计算开始"); sw.Restart(); Semaphore semaphore = new Semaphore(0, count); System.Threading.Tasks.Parallel.For(0, count, i => { results[i] = CalculateA(i); semaphore.Release(); }); for (var i = 0; i < count; i++) { semaphore.WaitOne(); //Console.WriteLine("Got " + i); } sw.Stop(); Console.WriteLine("并行计算,总耗时{0}", sw.ElapsedTicks); Console.WriteLine("Result:{0}", results[0] + "#" + results[1] + "#" + results[2] + "#" + results[3] + "#" + results[4] + "#" + results[5] + "#" + results[6] + "#" + results[7] + "#" + results[8] + "#" + results[9] ); Console.ReadLine(); } private static int CalculateA(int inputValue) { int result =0; ///模拟大量的计算 for (int i = 0; i < 100000000; i++) { result += inputValue; } return result; } private static void CalculateB(object inputValue) { int n = (int)inputValue; int result = 0; ///模拟大量的计算 for (int i = 0; i < 100000000; i++) { result += n; } results[n] = result ; rets[n].Set(); } }
测试结果见下图
我的机器是4核处理器,从测试结果看,并行计算,当计算量越大的时候,计算时间越接近于普通计算的 四分之一(处理器是4核),使用线程池的计算时间略多于TPL,
不过不是很明显,看来线程池也是重复利用了多核的优势,不过对于for 和 foreach 之类的大量运算,TPL 写起来很简洁,以后在项目中多尝试使用。