Parallel.For
Parallel.For 你可能忽视的一个非常实用的重载方法
说起Parallel.For大家都不会陌生,很简单,不就是一个提供并行功能的for循环吗? 或许大家平时使用到的差不多就是其中最简单的那个重载方法,而真实情况
下Parallel.For里面有14个重载,而其中那些比较复杂的重载方法,或许还有同学还不知道怎么用呢~~~ 刚好我最近我有应用场景了,给大家介绍介绍,废话不多说,
先给大家看一下这个并行方法的重载一览表吧。。。

一:遇到的场景
我遇到的场景是这样的,项目中有这样一个功能,这个功能需要根据多个维度对一组customerIDList进行筛选,最后求得多个维度所筛选出客户的并集,我举个
例子:现有8个维度:
1. 交易行为
2.营销活动
3.地区
4.新老客户
5.营销渠道
6.客户属性
7.客户分组
8.商品
每个维度都能筛选出一批customerid出来,然后对8组customerid求并集,这种场景很明显要提升性能的话,你必须要做并行处理,当然能够实现的方式有很多种,
比如我定义8个task<T>,然后使用WaitAll等待一下,最后再累计每个Result的结果就可以了,代码如下:

1 class Program
2 {
3 static void Main(string[] args)
4 {
5 List<string> rankList = Enum.GetNames(typeof(FilterType)).ToList();
6
7 Task<HashSet<int>>[] tasks = new Task<HashSet<int>>[rankList.Count];
8
9 var hashCustomerIDList = new HashSet<int>(); //求customerid的并集
10
11 for (int i = 0; i < tasks.Length; i++)
12 {
13 tasks[i] = Task.Factory.StartNew<HashSet<int>>((obj) =>
14 {
15 //业务方法,耗损性能中。。。
16 var smallCustomerIDHash = GetXXXMethod(rankList[(int)obj]);
17
18 return smallCustomerIDHash;
19 }, i);
20 }
21
22 Task.WaitAll(tasks);
23
24 foreach (var task in tasks)
25 {
26 foreach (var item in task.Result)
27 {
28 hashCustomerIDList.Add(item);
29 }
30 }
31 }
32
33 static HashSet<int> GetXXXMethod(string rank)
34 {
35 return new HashSet<int>();
36 }
37
38 public enum FilterType
39 {
40 交易行为 = 1,
41 营销活动 = 2,
42 地区 = 4,
43 新老客户 = 8,
44 营销渠道 = 16,
45 客户属性 = 32,
46 客户分组 = 64,
47 商品 = 128
48 }
49 }

上面的代码的逻辑还是很简单的,我使用的是Task<T>的模式,当然你也可以用void形式的Task,然后在里面lock代码的时候对hashCustomerIDList进行
插入,实现起来也是非常简单的,我就不演示了,那下面的问题来了,有没有更爽更直接的方式,看人家看上去更有档次一点的方法,而且还要达到这种效果呢?
二:Parallel.For复杂重载
回到文章开头的话题,首先我们仔细分析一下下面这个复杂的重载方法。

1 //
2 // 摘要:
3 // 执行具有线程本地数据的 for(在 Visual Basic 中为 For)循环,其中可能会并行运行迭代,而且可以监视和操作循环的状态。
4 //
5 // 参数:
6 // fromInclusive:
7 // 开始索引(含)。
8 //
9 // toExclusive:
10 // 结束索引(不含)。
11 //
12 // localInit:
13 // 用于返回每个任务的本地数据的初始状态的函数委托。
14 //
15 // body:
16 // 将为每个迭代调用一次的委托。
17 //
18 // localFinally:
19 // 用于对每个任务的本地状态执行一个最终操作的委托。
20 //
21 // 类型参数:
22 // TLocal:
23 // 线程本地数据的类型。
24 //
25 // 返回结果:
26 // 包含有关已完成的循环部分的信息的结构。
27 //
28 // 异常:
29 // T:System.ArgumentNullException:
30 // body 参数为 null。- 或 -localInit 参数为 null。- 或 -localFinally 参数为 null。
31 //
32 // T:System.AggregateException:
33 // 包含在所有线程上引发的全部单个异常的异常。
34 public static ParallelLoopResult For<TLocal>(int fromInclusive, int toExclusive, Func<TLocal> localInit, Func<int, ParallelLoopState, TLocal, TLocal> body, Action<TLocal> localFinally);

从上面的代码区域中看,你可以看到上面提供了5个参数,而最后意思的就是后面三个,如果你对linq的扩展方法比较熟悉的话,你会发现这个其实就是一个并行版本
的累加器(Aggregate)操作,因为他们都是具有三个区域:第一个区域就是初始化区域(localInit),就是累积之前的一个初始化操作,第二个区域其实就是一个迭代
区域,说白了就是foreach/for循环,for循环之中,会把计算结果累计到当初初始化区域设置的变量中,第三个区域就是foreach/for之后的一个最终计算区,三者合起
来就是一个并行累加器,为了方便大家更好的理解,我就扒一下源码给大家看看:


由于图太大,就截两张图了,大家一定要仔细体会一下这里面的tlocal变量,因为这个tlocal的使用贯穿着三个区域,所以大家一定要好好体会下面这几句代码

1 TLocal tLocal = default(TLocal);
2
3 tLocal = localInit();
4
5 while(xxx<xxx){
6 tLocal = bodyWithLocal(num5, parallelLoopState, tLocal);
7 }
8 localFinally(tLocal);

当你理解了tLocal具有累积foreach中的item结果之后,你就应该很明白下面这个body=>(item, loop, total) 和 finally => (total) 中total的含义了,
对吧,当你明白了,然后大家可以看看下面这段代码,是不是用一个方法就搞定了原来需要分阶段实现的一个业务逻辑呢?
class Program
{
static void Main(string[] args)
{
List<string> rankList = Enum.GetNames(typeof(FilterType)).ToList();
var hashCustomerIDList = new HashSet<int>(); //求customerid的并集
//并行计算 7个 维度的 总和
Parallel.For(0, rankList.Count, () => { return new List<int>(); }, (item, loop, total) =>
{
//业务方法,耗损性能中。。。
var smallCustomerIDHash = GetXXXMethod(rankList[item]);
total.AddRange(smallCustomerIDHash);
return total;
}, (total) =>
{
lock (hashCustomerIDList)
{
foreach (var customerID in total)
{
hashCustomerIDList.Add(customerID);
}
}
});
}
static HashSet<int> GetXXXMethod(string rank)
{
return new HashSet<int>();
}
public enum FilterType
{
交易行为 = 1,
营销活动 = 2,
地区 = 4,
新老客户 = 8,
营销渠道 = 16,
客户属性 = 32,
客户分组 = 64,
商品 = 128
}
}
Parallel.For的更多相关文章
- .Net多线程编程—System.Threading.Tasks.Parallel
System.Threading.Tasks.Parallel类提供了Parallel.Invoke,Parallel.For,Parallel.ForEach这三个静态方法. 1 Parallel. ...
- Java 8函数编程轻松入门(五)并行化(parallel)
1.并发与并行的区别 并发: 一个时间段内有几个程序都处于已启动到运行完毕之间,且这几个程序都是在同一个处理机上运行.但在任一个时刻点只有一个程序在处理机上运行 并行: 在同一个时刻,多核处理多个任务 ...
- Parallel并行之乱用
关于Parallel我也不细说了,一则微软封装的很好用,二来介绍这个的遍地都是. 我要说的是,要想成为一个优秀的标题党,一定要把重点放到别的地方,为了节省大家阅读时间,我先把结论说了,然后再慢慢从头说 ...
- 代码的坏味道(12)——平行继承体系(Parallel Inheritance Hierarchies)
坏味道--平行继承体系(Parallel Inheritance Hierarchies) 平行继承体系(Parallel Inheritance Hierarchies) 其实是 霰弹式修改(Sho ...
- 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel)
Task - 基于线程池的任务(在 System.Threading.Tasks 命名空间下) 多 Task 的并行执行 Parallel - 并行计算(在 System.Threading.Task ...
- Parallel.Foreach
随着多核时代的到来,并行开发越来越展示出它的强大威力! 使用并行程序,充分的利用系统资源,提高程序的性能.在.net 4.0中,微软给我们提供了一个新的命名空间:System.Threading.Ta ...
- 在Parallel中使用DbSet.Add()发现的一系列多线程问题和解决过程
发现问题 需求很简单,大致就是要批量往数据库写数据,于是打算用Parallel并行的方式写入,希望能利用计算机多核特性加快程序执行速度.想的很美好,于是快速撸了类似下面的一串代码: using (va ...
- Intel.parallel.studio.xe.2015.Update.2.ISO-TBE 下载
磁力链下载点我 还有linux版本 Intel.parallel.studio.xe.2015.Update.1.LINUX.ISO-TBE 收集自网络,要跨请跨原作者,谢谢.
- Parallel并行编程初步
Parallel并行编程可以让我们使用极致的使用CPU.并行编程与多线程编程不同,多线程编程无论怎样开启线程,也是在同一个CPU上切换时间片.而并行编程则是多CPU核心同时工作.耗时的CPU计算操作选 ...
- C#~异步编程再续~大叔所理解的并行编程(Task&Parallel)
返回目录 并行这个概念出自.net4.5,它被封装在System.Threading.Tasks命名空间里,主要提供一些线程,异步的方法,或者说它是对之前Thread进行的二次封装,为的是让开发人员更 ...
随机推荐
- CentOS 7 virt-manager 无法连接本地的hypervisor
OS : CentOS 7 Gnome Desktop 问题描写叙述: CentOS 7 下使用yum install virt-manager之后.使用virt-manager无法连接本地的hype ...
- 关于Android中设置闹钟的相对比较完善的解决方案
我当时说承诺为大家写一个,一直没空,直到最近又有人跟我要,我决定抽时间写一个吧.确实设置闹钟是一个比较麻烦的东西.我在这里写的这个demo抽出来了封装了一个类库,大家直接调用其中的设置闹钟和取消闹钟的 ...
- TreeView控件的展开与折叠
在窗体中添加一个TreeView控件,设置CheckBox属性为True,绑定数据 Archive jkj = new Archive();//自定义类 public void Bind ...
- 谈谈我对P2P网络借贷的一些看法
北漂期间,只知道互联网金融非常火,相关创业公司和项目也非常多.2013年,最火的是余额宝等宝宝类产品.当时的收益率达到了7%,流动性如此高的情况下,竟达到这么高的收益率,我简直不敢相信.另外,当时考虑 ...
- [Angular2 Animation] Delay and Ease Angular 2 Animations
By default, transitions will appear linearly over time, but proper animations have a bit more custom ...
- 用strace排查故障的5种简单方法(每日一译)
原文链接:5 simple ways to troubleshoot using Strace 我很意外大部分人都不知道如何使用strace.strace一直是我的首选debug工具,因为它非常的有效 ...
- 【77.78%】【codeforces 625C】K-special Tables
time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...
- JS实现页面table鼠标移动改变tr行颜色,单击tr选中复选框功能
JS源代码: //需要设置tr背景颜色 var highlightcolor='#bfecfc'; //设置背景颜色 function changeto(index){ var tr1 = docum ...
- php实现二叉树的镜像(二叉树就是递归)
php实现二叉树的镜像(二叉树就是递归) 一.总结 二叉树就是递归 二.php实现二叉树的镜像 题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / ...
- ebook https://salttiger.com/category/notification/
https://salttiger.com/category/notification/ 因为个人精力有限,持续搜集.整理.分享电子书已经占用我大部分业余时间,今后不再给评论区留言的朋友们找书,还希望 ...