1、简介

关于Parallel不想说太多,因为它是Task的语法糖,至少我是这么理解的,官方文档也是这么说的,它本身就是基本Task的.假设我们有一个集合,不管是什么集合,我们要遍历它,首先想到的是For(如何涉及到修改或者读可以用for)或者Foreach(如果单纯的读),但是它两是同步的去操作集合,但是使用Parallel的静态For或者Foreach那就可以让多个线程参与这个工作,这样就能充分的利用CPU,但是你需要考虑CPU上下文产生的性能消耗,以及Parallel本身的性能消耗,所以,这也能解释为什么,你的循环里面执行的是不耗时的操作,使用for或者foreach的速度比使用Parallel的要快,所以使用Parallel还是要慎重.而且使用Parallel还需要注意的一点就是,不能有多线程争用问题,就是你的循环体里面不能有操作静态资源的操作.如果真的需要,那你可以加锁,但是那就失去它的优势了.

2、使用注意点

(1)、不能操作共享资源,代码如下:

        static int shareData = 10;static void Main(string[] args){Parallel.For(1, 100000, i => Add(i));Console.Write(shareData);Console.ReadKey();}static void Add(int i){shareData += i;}

代码逻辑很简单,1+2+3+......+100000这个过程中每次都加一个10,怎么说都是正数,但是,信不信它能给你加出个负数来(可能是内存溢出了),而且每次的结果都不一样(重要)!自己试试吧!

解决方案很简单,加个锁,代码如下:

    class ParallerStudy{static int shareData = 10;static object lockObj = new object();static void Main(string[] args){Parallel.For(1, 100000, i => Add(i));Console.Write(shareData);Console.ReadKey();}static void Add(int i){lock (lockObj){shareData += i;}}}

这个肯定是正确的值,因为每次的输出都是这个,这里因为如果给循环的最终值设小的话,他好像是同步去做了,不会有问题,所以这里给了个100000,这个时候它会开多个线程去做.

(2)、它可以向Task一样抛出异常,都是AggregateException,代码如下:

这里就给截图了,不写代码了.

(3)、性能开销

这个不用多说,它是基于Task,开销还是有的,如果不清楚,去看我前面的文章

(4)、支持取消

取消貌似只能取消整个Parallel运算,不支持取消内部的方法,我试了不行,而且必须在执行Parallel之前取消它,之后都不行.很其怪,可能我的调用方式有问题,如果你们有好的方法,欢迎在下面评论.

(4)、可以设置最多的线程数

实战中有演示

(5)、调度器

这里就不介绍了,后续的随笔中会介绍

(6)、三个重要的委托

实战中有演示

3、实战

(1)、下面写个使用Parallel多线程去读文件的例子

代码如下:

    class ParallerStudy{static void Main(string[] args){var targetPath = $"{AppDomain.CurrentDomain.BaseDirectory}Test";var totalLength = DictionaryFilesContent(targetPath, "", SearchOption.TopDirectoryOnly);Console.WriteLine("{0}目录下所有的文件长度总和为:{1}", targetPath, totalLength);Console.ReadKey();}/// <summary>/// 多线程读取多个文件的内容/// </summary>/// <param name="i"></param>/// <returns></returns>static long DictionaryFilesContent(string path, string searchPattern, SearchOption searchOptions){var opts = new ParallelOptions();//只允许开六个线程去做这个事情opts.MaxDegreeOfParallelism =3;var files = Directory.EnumerateFiles(path);long totalFileLength = 0;Parallel.ForEach<string, long>(files,opts,//初始委托,该方法会在线程执行主要任务前执行,可用于参数校验等操作() =>{Console.WriteLine("开启读取文件,当前线程Id为{0}", Thread.CurrentThread.ManagedThreadId);return 0;},//主体委托,开始干正事(file, loopstate, index, taskLocalCount) =>{long fileLength = 0;FileStream fs = null;try{fs = File.OpenRead(file);fileLength = fs.Length;Console.WriteLine("当前线程Id为{1},当前文件名为{2}", index, Thread.CurrentThread.ManagedThreadId, fs.Name);}catch (IOException) { }//排除拒绝访问的文件finally{if (fs != null)fs.Dispose();}return taskLocalCount + fileLength;},//终结委托,一般用于汇总主体委托的结果值,所以如果这里涉及访问共享资源的话,一般会用同步构造,也就是加锁等操作taskLocalCount =>{//taskLocalCount=taskLocalCount + fileLength,单个文件的长度//同步构造,不需要加锁,当每个线程读取完对应文件的长度后,将长度加到totalFileLength中,这个时候多个线程访问这个变量可能会出现//多线程争用问题,但是使用Interlocked.Add相当与给totalFileLength加锁Interlocked.Add(ref totalFileLength, taskLocalCount);});return totalFileLength;}}

看这个例子前,还在想真的有这么厉害吗?其实也就那样,根据输出可以发现,一个开了3个线程,去读10个文件,我还在想这里面会不会有多线程争用问题,但是没有,你看它怎么做的,每个线程只会去读一个文件,读的快的,立即去读另外的文件,我执行了N次,发现并没有一个文件多个线程读的问题,所以每个线程只会去读一个文件,自然就不会有多线程争用问题了.

(2)、关于ParallelLoopState的用法

Stop()和Break方法最常用,当子任务处理批量的任务时,如果满足某种条件,则告诉其余的任务不需要在处理了.

这个对象主要用于Parallel开启的子任务群,它们内部之间的交流,代码如下:

        static void Main(string[] args){var targetPath = $"{AppDomain.CurrentDomain.BaseDirectory}Test";var totalLength = DictionaryFilesContent(targetPath, "", SearchOption.TopDirectoryOnly);Console.WriteLine("{0}目录下所有的文件长度总和为:{1}", targetPath, totalLength);Console.ReadKey();}/// <summary>/// 多线程读取多个文件的内容/// </summary>/// <param name="i"></param>/// <returns></returns>static long DictionaryFilesContent(string path, string searchPattern, SearchOption searchOptions){var opts = new ParallelOptions();//只允许开六个线程去做这个事情opts.MaxDegreeOfParallelism =3;var files = Directory.EnumerateFiles(path);long totalFileLength = 0;Parallel.ForEach<string, long>(files,opts,//初始委托,该方法会在线程执行主要任务前执行,可用于参数校验等操作() =>{Console.WriteLine("开启读取文件,当前线程Id为{0}", Thread.CurrentThread.ManagedThreadId);return 0;},//主体委托,开始干正事(file, loopstate, index, taskLocalCount) =>{long fileLength = 0;FileStream fs = null;try{//处理完第3项,就不要在处理了,这个第三项的意思是不是第三个文件,也可能是第五个文件if (index == 3){loopstate.Stop();}fs = File.OpenRead(file);fileLength = fs.Length;Console.WriteLine("当前线程Id为{1},当前文件名为{2}", index, Thread.CurrentThread.ManagedThreadId, fs.Name);}catch (IOException) { }//排除拒绝访问的文件finally{if (fs != null)fs.Dispose();}return taskLocalCount + fileLength;},//终结委托,一般用于汇总主体委托的结果值,所以如果这里涉及访问共享资源的话,一般会用同步构造,也就是加锁等操作taskLocalCount =>{//taskLocalCount=taskLocalCount + fileLength,单个文件的长度//同步构造,不需要加锁,当每个线程读取完对应文件的长度后,将长度加到totalFileLength中,这个时候多个线程访问这个变量可能会出现//多线程争用问题,但是使用Interlocked.Add相当与给totalFileLength加锁Interlocked.Add(ref totalFileLength, taskLocalCount);});return totalFileLength;}

还有其它的一些用法,这里就不介绍了,Api里面都有介绍.

(3)、Parallel的返回值

就说一个LowestBreakIteration,如果这个返回值为null,说明子任务群有个调用了Stop方法,如果不为null,说明有个调用了Break方法且值为调用Break任务对应的Index值.

转载于:https://www.cnblogs.com/GreenLeaves/p/10090047.html

C# 多线程七之Parallel相关推荐

  1. 多线程七种执行的状态

    初始化状态 就绪状态 运行状态 死亡状态 阻塞状态 超时等待 等待状态 start():调用start()方法会使得该线程开始执行,正确启动线程的方式. wait():调用wait()方法,进入等待状 ...

  2. (七)Java垃圾收集器详解

    面试官问:Java垃圾收集器了解过多少,说一下 JVM 有哪些垃圾回收器?这些问题在你面试高级Java的时候经常会问到.本篇文章结合着[深入理解Java虚拟机]一书当中整理了本篇博客. 如果想要对收集 ...

  3. 【Netty】反应器 Reactor 模式 ( 单反应器 Reactor 单线程 | 单反应器 Reactor 多线程 )

    文章目录 一. 反应器 ( Reactor ) 模式 二. 反应器 ( Reactor ) 模式两大组件 三. 单反应器 ( Reactor ) 单线程 四. 单反应器 ( Reactor ) 单线程 ...

  4. Serial Old收集器和Parallel Old收集器

    Serial Old收集器 Serial Old是 Serial收集器的老年代版本: 1.特点 针对老年代: 采用"标记-整理"算法(还有压缩,Mark-Sweep-Compact ...

  5. 深入多线程九:守护线程(代码示例)

    在学习Java的道路上,是否路过多线程时总让你很迷惘:很不巧,我也是,而使我们感到很迷惘主要原因都源于没有对概念的深深的理解和实践.所以我决定漫步Java多线程,同你一起会会多线程. 深入多线程系列 ...

  6. C#编程,Parallel类实现数据并行与任务并行

    一.Parallel类 Parallel类提供了数据和任务的并行性: 二.Paraller.For() Paraller.For()方法类似于C#的for循环语句,也是多次执行一个任务.使用Paral ...

  7. Jvm 系列(八):Jvm 知识点总览

    对于Java程序员来讲,spring全家桶几乎可以搞定一切,spring全家桶便是精妙的招式,jvm就是内功心法很重要的一块,线上出现性能问题,jvm调优更是不可回避的问题.因此JVM基础知识对于高级 ...

  8. jvm系列(八):jvm知识点总览-高级Java工程师面试必备

    在江湖中要练就绝世武功必须内外兼备,精妙的招式和深厚的内功,武功的基础是内功.对于武功低(就像江南七怪)的人,招式更重要,因为他们不能靠内功直接去伤人,只能靠招式,利刃上优势来取胜了,但是练到高手之后 ...

  9. java面试题(转载其他人,方便日常看)

    序言 在本篇文章开始之前,我想先来回答一个问题:我为什么要写这样一篇关于面试的文章?原因有三个:第一,我想为每一个为梦想时刻准备着的"有心人",尽一份自己的力量,提供一份高度精华的 ...

  10. jvm系列(八):jvm知识点总览

    在江湖中要练就绝世武功必须内外兼备,精妙的招式和深厚的内功,武功的基础是内功.对于武功低(就像江南七怪)的人,招式更重要,因为他们不能靠内功直接去伤人,只能靠招式,利刃上优势来取胜了,但是练到高手之后 ...

最新文章

  1. CSS_文字与特殊符号浏览器兼容性
  2. GB4208中规定的外壳防护等级IP
  3. return ,continue,break的用法与区别总结
  4. 手写call,apply
  5. SQLi LABS Less-21
  6. linux下sort详解(sort对科学记数法的排序)
  7. 每秒处理10万高并发订单的乐视集团支付系统架构分享
  8. Java程序开发过程
  9. Jenkins(03):配置Jenkins自动发送邮件
  10. 大学计算机品牌活动总结,【推荐】大学工作总结4篇
  11. 从360图书馆抓取全球国家的中文名与英文名(requests_html)
  12. 同一个表单form,两个按钮button,调用同一个submit(),给action附不同的参数
  13. ArrayList和LinkedList时间、空间复杂度对比
  14. android 跨屏效果图,手机电脑二合一:小米妙享跨屏协作正式上线
  15. 爬取网易云在线课程并保存到Excel
  16. iMonitor 365 远程监控软件怎样管理员工电脑?
  17. 谢国忠:“日本病”威胁全球
  18. html的炫彩字体怎么弄
  19. 中国水解乳清蛋白行业市场供需与战略研究报告
  20. 超强图解Pandas18招,墙裂建议收藏!

热门文章

  1. Atitit 索引法 html文件转txt纯文本索引 适用于 evernote索引,导入imap邮箱,方便检索 /sumdoclist/src/aPkg/html2txtIndexFile.jav
  2. Atitit java读取堵塞cmd命令行返回结果 java read maven 主要原理是另外线程读取标准流,错误流。。 回显增加out头,这样发布区分errstream和stdstream的
  3. atitit.http get post的原理以及框架实现java php
  4. paip.配置ef_unified_filter() failed ext_filter_module mod_ext_filter.so apache 错误解决
  5. paip.图片搜索工具总结
  6. paip.提升效率----更改数组LIST对象值for与FOREACH
  7. paip.账务系统的安全性
  8. 创金合信: 做的这些事
  9. (转)超越文艺复兴,Two Sigma成为全球量化基金新霸主
  10. Rust :公钥、私钥与keypair、signature、verify 三部曲