C#并行化Parallel简单使用示例
2014-04-14 19:52 hduhans 阅读(559) 评论(0) 编辑 收藏 举报.NET Framework 4.0中的TPL(Task Parallel Library)支持了并行化计算,可合理地运用在实际项目开发过程中,以提高程序的执行效率。
1、Parallel.For循环
本例分别对普通遍历求和计算NoParallel,无同步Lock的并行化求和计算ParallelNoLock和并行化求和有同步的Lock并行化求和计算ParallelLock执行了5次计算,这三个方法都做相同的事情,就是计算1-20的和并在每次循环后线程休眠50毫秒(模拟真实大运算环境),程序代码及运行结果如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A { //普通遍历求和计算 public void NoParallel(int times) { Stopwatch sw = Stopwatch.StartNew(); int result = 0; for (int i = 0; i < times; i++) { result += i; Thread.Sleep(50); //为模拟大量计算,线程休眠50毫秒,下同 } Console.WriteLine("普通遍历,结果:{0},耗时:{1}毫秒",result,sw.ElapsedMilliseconds); } //使用了并行化求和计算,没有同步Lock public void ParallelNoLock(int times) { Stopwatch sw = Stopwatch.StartNew(); int result = 0; Parallel.For(0, times, i => { result += i; Thread.Sleep(50); }); Console.WriteLine("并行遍历(无Lock),结果:{0},耗时:{1}毫秒", result, sw.ElapsedMilliseconds); } private Object syncHandle = new object(); //使用了并行化求和计算,使用了同步Lock public void ParallelLock(int times) { Stopwatch sw = Stopwatch.StartNew(); int result = 0; Parallel.For(0, times, i => { lock (syncHandle) { result += i; } Thread.Sleep(50); }); Console.WriteLine("并行遍历(有Lock),结果:{0},耗时:{1}毫秒", result, sw.ElapsedMilliseconds); } } //调用 A a = new A(); Console.WriteLine("普通遍历=>"); for (int i = 0; i < 5; i++) { a.NoParallel(20); } Console.WriteLine("并行遍历(无Lock)=>"); for (int i = 0; i < 5; i++) { a.ParallelNoLock(20); } Console.WriteLine("并行遍历(有Lock)=>"); for (int i = 0; i < 5; i++) { a.ParallelLock(20); }
执行结果如下:
从结果可知,使用Parallel.For并行化遍历时,效率比普通for循环效率高好多倍,但是由于Parallel使用了多线程,为保证程序的可再现性,必须使用同步Lock。
2、Parallel.ForEach循环
本例将Customer对象序列化成XMl并保存到字典Dictionary中,比较了传统的实现方式和并行化的实现方式效率的差别。代码即运行结果如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class ParallelForEach { //自定义Customer类型 public class Customer { public long ID { get; set; } public String Name { get; set; } public override string ToString() { return Name; } } //普通处理方式 public static Dictionary<long,String> SerializeCustomers(Customer[] customers) { var dict = new Dictionary<long, string>(); var xmlSerializer = new XmlSerializer(typeof(Customer)); foreach (var customer in customers) { using (var ms = new MemoryStream()) { xmlSerializer.Serialize(ms, customer); dict.Add(customer.ID,Encoding.ASCII.GetString(ms.ToArray())); } Thread.Sleep(50); } return dict; } //并行化处理方式 public static Dictionary<long, String> ParallelSerializeCustomers(Customer[] customers) { var dict = new Dictionary<long, string>(); var xmlSerializer = new XmlSerializer(typeof(Customer)); object lockObj = new object(); Parallel.ForEach(customers, () => new Dictionary<long, String>(), (customer, loopState,lo,single) => { using (var ms = new MemoryStream()) { xmlSerializer.Serialize(ms, customer); single.Add(customer.ID, Encoding.ASCII.GetString(ms.ToArray())); } return single; }, (single) => { lock (lockObj) { single.ToList().ForEach(p=>dict.Add(p.Key,p.Value)); } Thread.Sleep(50); } ); return dict; } } //执行测试 ParallelForEach.Customer[] customers = new ParallelForEach.Customer[50]; for (int i = 0; i < customers.Length; i++) { customers[i] = new ParallelForEach.Customer() { ID = i, Name = "name" + i.ToString() }; } //执行耗时2657ms Dictionary<long, String> dic1 = ParallelForEach.SerializeCustomers(customers); //执行耗时65ms Dictionary<long, String> dic2 = ParallelForEach.ParallelSerializeCustomers(customers);
执行结果分别为2657ms和65ms,可知并行化计算效率比普通遍历效率高。
3、适用环境
并非任何环境都适合多线程并行化计算,也即并非多线程一定能提高效率,其适用条件如下:
1) 运行环境是多核操作系统;
2) 执行任务并非纯运算,因为纯运算任务使用多线程反而会降低效率;
3) 任务中有缓冲操作,如I/O操作,读数据库等操作;