5天玩转C#并行和多线程编程系列文章目录

5天玩转C#并行和多线程编程 —— 第一天 认识Parallel

5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq

5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task

5天玩转C#并行和多线程编程 —— 第四天 Task进阶

5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结

  随着多核时代的到来,并行开发越来越展示出它的强大威力!使用并行程序,充分的利用系统资源,提高程序的性能。在.net 4.0中,微软给我们提供了一个新的命名空间:System.Threading.Tasks。这里面有很多关于并行开发的东西,今天第一篇就介绍下最基 础,最简单的——认识和使用Parallel。

  一、 Parallel的使用

在Parallel下面有三个常用的方法invoke,For和ForEach。

1、  Parallel.Invoke

这是最简单,最简洁的将串行的代码并行化。

在这里先讲一个知识点,就是StopWatch的使用,最近有一些人说找不到StopWatch,StopWatch到底是什么东西,今天就来说明一下。

StopWatch在System.Diagnostics命名控件,要使用它就要先引用这个命名空间。

其使用方法如下:

var stopWatch = new StopWatch();   //创建一个Stopwatch实例

stopWatch.Start();   //开始计时

stopWatch.Stop();   //停止计时

stopWatch.Reset();  //重置StopWatch

stopWatch.Restart(); //重新启动被停止的StopWatch

stopWatch.ElapsedMilliseconds //获取stopWatch从开始到现在的时间差,单位是毫秒

本次用到的就这么多知识点,想了解更多关于StopWatch的,去百度一下吧,网上有很多资料。

下面进入整体,开始介绍Parallel.Invoke方法,废话不多说了,首先新建一个控制台程序,添加一个类,代码如下:

  1. public class ParallelDemo
  2. {
  3. private Stopwatch stopWatch = new Stopwatch();
  4.  
  5. public void Run1()
  6. {
  7. Thread.Sleep(2000);
  8. Console.WriteLine("Task 1 is cost 2 sec");
  9. }
  10. public void Run2()
  11. {
  12. Thread.Sleep(3000);
  13. Console.WriteLine("Task 2 is cost 3 sec");
  14. }
  15.  
  16. public void ParallelInvokeMethod()
  17. {
  18. stopWatch.Start();
  19. Parallel.Invoke(Run1, Run2);
  20. stopWatch.Stop();
  21. Console.WriteLine("Parallel run " + stopWatch.ElapsedMilliseconds + " ms.");
  22.  
  23. stopWatch.Restart();
  24. Run1();
  25. Run2();
  26. stopWatch.Stop();
  27. Console.WriteLine("Normal run " + stopWatch.ElapsedMilliseconds + " ms.");
  28. }

代码很简单,首先新加一个类,在类中写了两个方法,Run1和Run2,分别等待一定时间,输出一条信息,然后写了一个测试方法ParallelInvokeMethod,分别用两种方法调用Run1和Run2,然后在main方法中调用,下面来看一下运行时间如何:

  大家应该能够猜到,正常调用的话应该是5秒多,而Parallel.Invoke方法调用用了只有3秒,也就是耗时最长的那个方法,可以看出方法是并行执行的,执行效率提高了很多。

2、Parallel.For

这个方法和For循环的功能相似,下面就在类中添加一个方法来测试一下吧。代码如下:

  1. public void ParallelForMethod()
  2. {
  3. stopWatch.Start();
  4. for (int i = 0; i < 10000; i++)
  5. {
  6. for (int j = 0; j < 60000; j++)
  7. {
  8. int sum = 0;
  9. sum += i;
  10. }
  11. }
  12. stopWatch.Stop();
  13. Console.WriteLine("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms.");
  14.  
  15. stopWatch.Reset();
  16. stopWatch.Start();
  17. Parallel.For(0, 10000, item =>
  18. {
  19. for (int j = 0; j < 60000; j++)
  20. {
  21. int sum = 0;
  22. sum += item;
  23. }
  24. });
  25. stopWatch.Stop();
  26. Console.WriteLine("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms.");
  27.  
  28. }

写了两个循环,做了一些没有意义的事情,目的主要是为了消耗CPU时间,同理在main方法中调用,运行结果如下图:

可以看到,Parallel.For所用的时间比单纯的for快了1秒多,可见提升的性能是非常可观的。那么,是不是Parallel.For在任何时候都比for要快呢?答案当然是“不是”,要不然微软还留着for干嘛?

下面修改一下代码,添加一个全局变量num,代码如下:

  1. public void ParallelForMethod()
  2. {
  3. var obj = new Object();
  4. long num = 0;
  5. ConcurrentBag<long> bag = new ConcurrentBag<long>();
  6.  
  7. stopWatch.Start();
  8. for (int i = 0; i < 10000; i++)
  9. {
  10. for (int j = 0; j < 60000; j++)
  11. {
  12. //int sum = 0;
  13. //sum += item;
  14. num++;
  15. }
  16. }
  17. stopWatch.Stop();
  18. Console.WriteLine("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms.");
  19.  
  20. stopWatch.Reset();
  21. stopWatch.Start();
  22. Parallel.For(0, 10000, item =>
  23. {
  24. for (int j = 0; j < 60000; j++)
  25. {
  26. //int sum = 0;
  27. //sum += item;
  28. lock (obj)
  29. {
  30. num++;
  31. }
  32. }
  33. });
  34. stopWatch.Stop();
  35. Console.WriteLine("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms.");
  36.  
  37. }

Parallel.For由于是并行运行的,所以会同时访问全局变量num,为了得到正确的结果,要使用lock,此时来看看运行结果:

  是不是大吃一惊啊?Parallel.For竟然用了15秒多,而for跟之前的差不多。这主要是由于并行同时访问全局变量,会出现资源争夺,大多数时间消耗在了资源等待上面。

一直说并行,那么从哪里可以看出来Parallel.For是并行执行的呢?下面来写个测试代码:

  1. Parallel.For(0, 100, i =>
  2. {
  3. Console.Write(i + "\t");
  4. });

从0输出到99,运行后会发现输出的顺序不对,用for顺序肯定是对的,并行同时执行,所以会出现输出顺序不同的情况。

2、Parallel.Foreach

这个方法跟Foreach方法很相似,想具体了解的,可以百度些资料看看,这里就不多说了,下面给出其使用方法:

  1. List<int> list = new List<int>();
  2. list.Add(0);
  3. Parallel.ForEach(list, item =>
  4. {
  5. DoWork(item);
  6. });
 二、 Parallel中途退出循环和异常处理

1、当我们使用到Parallel,必然是处理一些比较耗时的操作,当然也很耗CPU和内存,如果我们中途向停止,怎么办呢?

在串行代码中我们break一下就搞定了,但是并行就不是这么简单了,不过没关系,在并行循环的委托参数中提供了一个ParallelLoopState,

该实例提供了Break和Stop方法来帮我们实现。

Break: 当然这个是通知并行计算尽快的退出循环,比如并行计算正在迭代100,那么break后程序还会迭代所有小于100的。

Stop:这个就不一样了,比如正在迭代100突然遇到stop,那它啥也不管了,直接退出。

下面来写一段代码测试一下:

  1. public void ParallelBreak()
  2. {
  3. ConcurrentBag<int> bag = new ConcurrentBag<int>();
  4. stopWatch.Start();
  5. Parallel.For(0, 1000, (i, state) =>
  6. {
  7. if (bag.Count == 300)
  8. {
  9. state.Stop();
  10. return;
  11. }
  12. bag.Add(i);
  13. });
  14. stopWatch.Stop();
  15. Console.WriteLine("Bag count is " + bag.Count + ", " + stopWatch.ElapsedMilliseconds);
  16. }

这里使用的是Stop,当数量达到300个时,会立刻停止;可以看到结果"Bag count is 300",如果用break,可能结果是300多个或者300个,大家可以测试一下。

2、异常处理

  首先任务是并行计算的,处理过程中可能会产生n多的异常,那么如何来获取到这些异常呢?普通的Exception并不能获取到异常,然而为并行诞生的AggregateExcepation就可以获取到一组异常。

这里我们修改Parallel.Invoke的代码,修改后代码如下:

  1. public class ParallelDemo
  2. {
  3. private Stopwatch stopWatch = new Stopwatch();
  4.  
  5. public void Run1()
  6. {
  7. Thread.Sleep(2000);
  8. Console.WriteLine("Task 1 is cost 2 sec");
  9. throw new Exception("Exception in task 1");
  10. }
  11. public void Run2()
  12. {
  13. Thread.Sleep(3000);
  14. Console.WriteLine("Task 2 is cost 3 sec");
  15. throw new Exception("Exception in task 2");
  16. }
  17.  
  18. public void ParallelInvokeMethod()
  19. {
  20. stopWatch.Start();
  21. try
  22. {
  23. Parallel.Invoke(Run1, Run2);
  24. }
  25. catch (AggregateException aex)
  26. {
  27. foreach (var ex in aex.InnerExceptions)
  28. {
  29. Console.WriteLine(ex.Message);
  30. }
  31. }
  32. stopWatch.Stop();
  33. Console.WriteLine("Parallel run " + stopWatch.ElapsedMilliseconds + " ms.");
  34.  
  35. stopWatch.Reset();
  36. stopWatch.Start();
  37. try
  38. {
  39. Run1();
  40. Run2();
  41. }
  42. catch(Exception ex)
  43. {
  44. Console.WriteLine(ex.Message);
  45. }
  46. stopWatch.Stop();
  47. Console.WriteLine("Normal run " + stopWatch.ElapsedMilliseconds + " ms.");
  48. }

顺序调用方法我把异常处理写一起了,这样只能捕获Run1的异常信息,大家可以分开写。捕获AggregateException 异常后,用foreach循环遍历输出异常信息,可以看到两个异常信息都显示了。

5天玩转C#并行和多线程编程的更多相关文章

  1. 5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结

    5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...

  2. 5天玩转C#并行和多线程编程 —— 第四天 Task进阶

    5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...

  3. 5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task

    5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...

  4. 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq

    5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...

  5. 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel

    5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...

  6. 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 转载 https://www.cnblogs.com/yunfeifei/p/3993401.html

    5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...

  7. C#并行和多线程编程

    5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq   5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线 ...

  8. C#并行和多线程编程_(1)认识Parallel

    Parallel: 英 [ˈpærəlel]    美 [ˈpærəˌlɛl] ,并联的,并行的. 随着多核时代的到来,并行开发越来越展示出它的强大威力!使用并行程序,充分的利用系统资源,提高程序的性 ...

  9. python 常见错误和异常 函数 正则表达式及多线程编程

    生成随机密码#!/usr/bin/env python import stringfrom random import choice def gen_pass(num=9): all_chs = st ...

随机推荐

  1. Mac下安装Wireshark,双击闪退

     Mac OS X上使用Wireshark抓包(http://blog.csdn.net/phunxm/article/details/38590561) Mac下安装Wireshark /Appli ...

  2. STM32学习笔记(六) SysTick系统时钟滴答实验(stm32中断入门)

    系统时钟滴答实验很不难,我就在面简单说下,但其中涉及到了STM32最复杂也是以后用途最广的外设-NVIC,如果说RCC是实时性所必须考虑的部分,那么NVIC就是stm32功能性实现的基础,NVIC的难 ...

  3. 20160824_CentOS6.4x64_关闭IPv6

    1.参考网址: http://blog.csdn.net/suplxj/article/details/7773423 2.我的操作: #cat <<EOF>>/etc/mod ...

  4. ionic build android--> Build failed with an exception. Execution failed for task ':processDebugResources'.

    执行 ionic build android,   ionic 自动化生成安卓apk包, 出现以上报错的原因为:打包的文件中含有中文名,把中文名的文件去掉或改名即可打包成功.

  5. js判断IE浏览器版本

    if(navigator.userAgent.indexOf("MSIE")>0){ if(navigator.userAgent.indexOf("MSIE 6. ...

  6. 编程之美----NIM游戏

    : 博弈游戏·Nim游戏 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 今天我们要认识一对新朋友,Alice与Bob.Alice与Bob总是在进行各种各样的比试,今天他 ...

  7. 10个优秀的JavaScript Web UI库/框架推荐

    在进行Web开发时,并非所有的库都适合你的项目,但你仍需要收藏一些Web UI设计相关的库或框架,以在你需要的时候,加快你的开发效率. 本文为你带来10款非常优秀的基于JavaScript的Web U ...

  8. JS 百度地图导航

    上一篇文章中我们就简单的学习了HTML5 地理定位,那么今天告诉大家我在项目中遇到的一个问题吧,就是怎么实现点击一个按钮就可以调到百度地图,并且获取到你当前的位置,并且导航到指定的地方去. 不想看步骤 ...

  9. ExtJS 刷新后,默认选中刷新前最后一次选中的节点

          在对树节点进行操作后往往需要进行reload操作刷新一下树,但是很多业务都需要在树形刷新后默认选中最后一次选中的节点.这样就必须先保存前一次选中节点的信息,在reload之后再次通过节点的 ...

  10. [vijos P1391] 想越狱的小杉

    考前最后一题,竟然是第一次码SPFA,虽然这个算法早有耳闻,甚至在闻所未闻之前自己有过一个类似的想法,说白了就是广搜啊,但是敲起来还是第一次啊,而且这还不是真正意义上的SPFA. 完全按照自己想法来码 ...