本文来自小易,【DoTNET技术圈】公众号已获得转载授权。

《.NET并发变成实战》读后感:并行编程Parallel

手打目录:

一、前言

二、任务并行库(TPL)的介绍

三、Parallel.Invoke的使用

四、Parallel.For的使用

五、Parallel.ForEach+Partitioner的使用

六、指定最大并行度MaxDegreeOfParallelism

七、退出循环以及捕捉异常

八、参考的资料

一、前言

背景:在物联网场景下,由于数据吞吐量较大,常规的Task异步执行存在明显的性能瓶颈,后通过参考Riccardo Terrel(里卡尔多Dian·特雷尔)著,叶伟民老师翻译的《.NET并发编程实战》,使用了Parallel并行编程,以及分区器Partitioner,将两者结合使用提高了设备数据绑定及数据更新速度,也做到了对CPU的性能比较极致使用。

萌新记录,大佬多加斧正!

可跳过概念,直接抵达使用实例—>五、Parallel.ForEach+Partitioner的使用

并行编程的原理

在《.net并发编程实战》(以下称《实战》)中这样解释并行编程——同时执行多个任务。

从开发人员的角度看,当我们考虑这些问题是,“我的程序可以同时执行多项操作吗?”或“我的程序如何更快地解决一个问题”我们会想到并行。并行是指同时在不同的内核上执行多个任务,以提高应用程序的速度,这需要硬件支持(多核),且并行只能在多核设备中实现,是提高程序性能和吞吐量的手段。

并行与并发编程简单区分

1、 并发编程一次处理多个操作,不需要硬件支持(使用一个或多个内核)。

2、 并行编程在多个CPU或多个内核上同时执行多个操作。所有并行程序都是并发的,同时运行的,但并非所有并发都是并行的。原因是并行只能在多核设备上实现。

3、 多任务同时执行来自不同进程的多个线程。多任务并不一定意味着并行执行,只有在使用多个CPU 或多个内核时才能实现并行执行。

为什么需要使用并行编程

《实战》对不同程序CPU使用资源使用的程度做了一个对比:

《实战》中认为,在一台多核计算机上运行一个没有考虑到并发的应用程序,就是在浪费计算机的生产力,因为应用程序在顺序处理过程中只能使用一部分可用的计算能力,在这种情况下任何CPU性能计数器会发现只有一个内核运行得很快,可能为100%,而其他内核未充分利用或空闲,在上图的8内核的计算机中,运行的非并行程序意味着资源的总体使用率可能不到15%。

使用并行编程的两种方式

1、 任务并行库(TPL),本文中只使用了这种方式

2、 并行LINQ(PLINQ)—》官方文档直达:https://docs.microsoft.com/zh-cn/dotnet/standard/parallel-programming/introduction-to-plinq

二、任务并行库(TPL)的并行介绍

.Net Framework4 引入了新的Task Parallel Library(任务并行库,TPL),它支持数据并行、任务并行和流水线。

当并行循环运行时,TPL会将数据源按照内置的分区算法(或者你可以自定义一个分区算法)将数据划分为多个不相交的子集,然后,从线程池中选择线程并行地处理这些数据子集,每个线程只负责处理一个数据子集。在后台,任务计划程序将根据系统资源和工作负荷来对任务进行分区。如有可能,计划程序会在工作负荷变得不平衡的情况下在多个线程和处理器之间重新分配工作。

在对任何代码(包括循环)进行并行化时,一个重要的目标是利用尽可能多的处理器,但不要过度并行化到使行处理的开销让任何性能优势消耗殆尽的程度。比如:对于嵌套循环,只会对外部循环进行并行化,原因是不会在内部循环中执行太多工作。少量工作和不良缓存影响的组合可能会导致嵌套并行循环的性能降低。

由于循环体是并行运行的,迭代范围的分区是根据可用的逻辑内核数、分区大小以及其他因素动态变化的,因此无法保证迭代的执行顺序。

TPL引入了System.Threading.Tasks ,主类是Task,这个类表示一个异步的并发的操作,然而我们不一定要使用Task类的实例,可以使用Parallel静态类。它提供了Parallel.Invoke Parallel.ForParallel.Forecah 三个方法,以下分别介绍3个方法的简单实例,每个方法都有多个重载,可自行查看源代码

三、Parallel.Invoke的使用

static void Main(){try{Parallel.Invoke(BasicAction,// Param #0 - 静态方法() =>// Param #1 - lambda表达式{Console.WriteLine("干饭人干饭, Thread={0}", Thread.CurrentThread.ManagedThreadId);},delegate ()// Param #2 -  委托{Console.WriteLine("委托方法中, Thread={0}", Thread.CurrentThread.ManagedThreadId);});}// 在本例中不期望出现异常,但如果任务中仍然抛出异常,// 它将被包装在AggregateException中,并传播到主线程。catch (AggregateException e){Console.WriteLine("捕捉异常 \n{0}", e.InnerException.ToString());}}static void BasicAction(){Console.WriteLine("打工人打工, Thread={0}", Thread.CurrentThread.ManagedThreadId);}

注解:

l 此方法可用于执行可能并行执行的一组操作。

l 不保证执行操作的顺序,或是否并行执行操作。

l 此方法在每个提供的操作都已完成后才会返回,无论是由于正常终止还是异常终止而发生。

四、Parallel.For的使用

我们先用一个简单的插入,来比较并行的for循环与串行for循环的速度。

这里因为Parallel.For在对处理器分配任务时候也有性能消耗,速度提升并不明显。

接下来我们看一下Parallel.For的其中重载之一

var list = new List<int>() { 10, 20, 30, 40 };
var options = new ParallelOptions();
var total = 0;
var result = Parallel.For(0, list.Count, () =>{Console.WriteLine("------------  thead --------------");return 1;},(i, loop, j) =>{Console.WriteLine("------------  body --------------");Console.WriteLine("i=" + list[i] + " j=" + j);return list[i];},(b) =>{Console.WriteLine("------------  tfoot --------------");Interlocked.Add(ref total, b);Console.WriteLine("total=" + total);
});Console.WriteLine("iscompleted:" + result.IsCompleted);
Console.Read();

注解:

l 因为并行任务当中不保证执行顺序,且多任务可能会同时尝试更新total变量,所以这里使用了 Interlocked.Add执行,来保证它是作为原子操作来执行。

五、Parallel.ForEach+Partitioner的结合使用

Partitioner分区器:

首先我们来看看分区器源代码,看他是如何对数据源进行分区的:

Partitioner.Create 若只指定的数据源的起始于结束的索引位置,创建分区则主要是根据逻辑内核数(PlatformHelper.ProcessorCount)决定的。

大部分情况下,TPL在幕后使用的负载均衡机制都是非常高效的,比如我们不使用分区器,直接对数据源进行负载均衡的并行执行,案例请看—>六、指定最大并行度。

当然我们也可以自定义分区大小,以下我们进入到实际的开发环境中,当前实验电脑为6核12线程处理器

注解:

dataList —>实时数据的数据源

Index —>数据源总数,此处假设1W条数据

rangesize—>区块大小,由此可以计算  10000/12+1=834(+1是为了适应可能除不尽的情况)

Partitioner.Create(0,Index,rangesize) —>分区器将数据源0-1W条数据分成了12个数据块,每一块为834条,当然最后一块没有834条数据

打上断点可以看到range.Item2-range.Item1=834,已经分好区块了,然后就是并行处理业务代码了。

这里贴上示例,粘贴可用:

int index = 10000;
var rangesize = (int)(index / Environment.ProcessorCount) + 1;
var rangePartitioner = Partitioner.Create(1, index, rangesize);
System.Threading.Tasks.Parallel.ForEach(rangePartitioner, range =>{#region 业务代码#endregion
});

六、指定最大并行度MaxDegreeOfParallelism

参考博客文章:Parallel.ForEach 之 MaxDegreeOfParallelism

https://www.cnblogs.com/QinQouShui/p/12134232.html

 System.Threading.Tasks.Parallel.ForEach(list, new ParallelOptions() { MaxDegreeOfParallelism = 12 }, range =>{#region 业务代码#endregion});

此Parallel.ForEach并没有使用分区器,而是用TPL进行负载均衡的并行。

该重载的源代码为:

七、退出循环以及捕捉异常

和串行运行中的break不同,ParallelLoopState 提供了两个方法用于停止Parallel.For 和 Parallel.ForEach的执行。

public class ParallelLoopState
{// 获取循环的任何迭代是否已引发相应迭代未处理的异常。public bool IsExceptional { get; }// 获取循环的任何迭代是否已调用 ParallelLoopState.Stop()。public bool IsStopped { get; }// 获取在Parallel循环中调用 ParallelLoopState.Break() 的最低循环迭代。public long? LowestBreakIteration { get; }// 获取循环的当前迭代是否应基于此迭代或其他迭代发出的请求退出。public bool ShouldExitCurrentIteration { get; }//通知Parallel循环当前迭代”之后”的其他迭代不需要运行。public void Break();//通知Parallel循环当前迭代“之外”的所有其他迭代不需要运行。public void Stop();
}

l Break:用于通知Parallel循环当前迭代“之后”的其他迭代不需要运行。例如,对于从 0 到 1000 并行迭代的 for 循环,如果在第 100 次迭代调用 Break(),则低于 100 的所有迭代仍会运行(即使还未开始处理),并在退出循环之前处理完。从 101 到 1000 中还未开启的迭代则会被放弃。对于已经在执行的长时间运行迭代,Break()将为已运行还未结束的迭代对应ParallelLoopResult结构的LowestBreakIteration属性设置为调用Bread()迭代项的索引。

l Stop:Stop() 用于通知Parallel循环当前迭代“之外”的所有其他迭代不需要运行,无论它们是位于当前迭代的上方还是下方。对于已经在执行的长时间运行迭代,可以检查 IsStopped属性,在观测到是 true 时提前退出。Stop 通常在基于搜索的算法中使用,在找到一个结果之后就不需要执行其他任何迭代。(比如在看视频或漫画时自动匹配响应最快的服务器)

var loopresult = System.Threading.Tasks.Parallel.ForEach(rangePartitioner, range =>
{#region 业务代码loopState.Stop();#endregion
});

当并行迭代中调用的委托抛出异常,这个异常没有在委托中被捕获到时,就会变成一组异常,新的System.AggregateException负责处理这一组异常。

try
{System.Threading.Tasks.Parallel.ForEach(rangePartitioner, range =>{#region 业务代码#endregion});
}
Catch(AggregateException ex)
{foreach (var innerEx in  ex.InnerExceptions){Console.WriteLine(innerEx.ToString());}
}

八、参考的资料

l 《.net并发编程实战》

l 官方文档《.NET 中的并行编程》https://docs.microsoft.com/zh-cn/dotnet/standard/parallel-programming/

l 博客园《.Net并行编程高级教程--Parallel》https://www.cnblogs.com/stoneniqiu/p/4857021.html

l 博客园《8天玩转并发》

https://www.cnblogs.com/huangxincheng/category/368987.html

l 《异步编程:.NET4.X 数据并行》

https://www.cnblogs.com/heyuquan/archive/2013/03/13/parallel-for-foreach-invoke.html

l 博客园《Parallel.ForEach 之 MaxDegreeOfParallelism》

https://www.cnblogs.com/QinQouShui/p/12134232.html

 end

输入优惠码同样也能享受到当当送的优惠。

RCKZEV(长按复制)10元优惠码(满99元可用)

7R99RD(长按复制)30元优惠码(满199元可用)

使用渠道:当当小程序或当当APP

有效期:3月23日至3月25日

如何运用并行编程Parallel提升任务执行效率相关推荐

  1. 深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)

    一. 并行编程 1. 区分串行编程和串行编程 ①. 串行编程:所谓的串行编程就是单线程的作用下,按顺序执行.(典型代表for循环 下面例子从1-100按顺序执行) ②. 并行编程:充分利用多核cpu的 ...

  2. 第九节:深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)

    一. 并行编程 1. 区分串行编程和串行编程 ①. 串行编程:所谓的串行编程就是单线程的作用下,按顺序执行.(典型代表for循环 下面例子从1-100按顺序执行) ②. 并行编程:充分利用多核cpu的 ...

  3. 并行算法 Parallel Algorithm -- 提高执行效率

    文章目录 1. 并行排序 2. 并行查找 3. 并行字符串匹配 4. 并行搜索 5. 总结 时间复杂度是衡量算法执行效率的一种标准.但是,时间复杂度 != 性能.即便在不降低时间复杂度的情况下,也可以 ...

  4. wordpress acf字段 不同样式_提升wordpress执行效率二次开发实录

    wordpress 对分类增加广告配置功能 wp_terms 增加admaster字段 varchar 200 wp-admin/edit-tag-form.php 小资料: wordpress wp ...

  5. C# SolidWorks 二次开发 API --- 提升exe执行效率接近DLL

    最近一段时间没更新博客,原因比较多.作为湖北人,今年的班上的不容易.当然还是要感谢各地的支援. 今天来和大家分享一下一个关于exe提升性能的选项,因为之前主要写的exe比较多,后来改成dll之后效率提 ...

  6. 《MATLAB专刊》——利用向量化编程提升MATLAB代码执行效率

    文章目录 1. 实验说明 2. 实验结果 3. 源程序 3.1 绘图源程序 3.2 测试源程序 4. 参考资料 为了阐明采用向量化编程思路对于MATLAB双重 forforfor循环优化的效果,本文通 ...

  7. dnet 并行编程学习总结

    .Net并行编程高级教程--Parallel http://www.cnblogs.com/stoneniqiu/p/4857021.html 一直觉得自己对并发了解不够深入,特别是看了<代码整 ...

  8. C#并行编程-并发集合

    菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...

  9. C#并行编程(1):理解并行

    什么是并行 并行是指两个或者多个事件在同一时刻发生. 在程序运行中,并行指多个CPU核心同时执行不同的任务:对于单核心CPU,严格来说是没有程序并行的.并行是为了提高任务执行效率,更快的获取结果. 与 ...

最新文章

  1. 前端的单页面模式和多页面模式
  2. nginx怎么部署php项目,nginx怎么正确部署前端项目
  3. 根据GPS经纬度查找指定范围内的对象
  4. 《移动项目实践》实验报告——Android高级控件
  5. 具有用户定义类型的format的示例用法
  6. 数据结构与算法之递归系列
  7. 从淘宝数据结构来看电子商务中商品属性设计
  8. 区块链爆史诗级漏洞,可完全控制虚拟货币交易!
  9. 当打开VS2013卡到吐,并且点一下卡一下
  10. 奈奎斯特定理和香农定理之科普篇
  11. c语言 dll库是线程安全吗,vsprintf是线程安全的吗?解决思路
  12. 小米个性主题显示服务器不可用,MIUI个性主题上线透明壁纸功能,并修复状态栏无法混搭问题!...
  13. 4.文件读取操作_read函数
  14. 去除取消WPS的广告推送、WPS热点以及推荐软件等骚扰功能
  15. cmd静默运行_如何在Win10上静默运行批处理文件
  16. 多用户在线书签管理工具My-BookMark
  17. JAVA中医药院校科研会议系统计算机毕业设计Mybatis+系统+数据库+调试部署
  18. 口袋之旅html5超强账号,口袋之旅h5高级账号,h5裂空座多少高级狩猎卷
  19. 老毛子、华硕固件USB连接打印机,普通打印机变无线打印机
  20. raphaeljs_矢量图形与raphaeljs

热门文章

  1. 聚类 python_python中实现k-means聚类算法详解
  2. 【CH4302】Interval GCD
  3. 安装mongoDB遇见的一个路径问题
  4. css_oneday
  5. C#控件绑定数据源方式
  6. Web前端笔试面试题汇总(转自github)
  7. 12月16日课程安排
  8. NOI导刊模拟2—电话网络 解题报告
  9. 解决VS2010 beta2 安装后html标签和script智能提示不起作用的问题
  10. 2007武汉.NET俱乐部沙龙-VS2008、WPF、Silverlight