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的更多相关文章

  1. .Net多线程编程—System.Threading.Tasks.Parallel

    System.Threading.Tasks.Parallel类提供了Parallel.Invoke,Parallel.For,Parallel.ForEach这三个静态方法. 1 Parallel. ...

  2. Java 8函数编程轻松入门(五)并行化(parallel)

    1.并发与并行的区别 并发: 一个时间段内有几个程序都处于已启动到运行完毕之间,且这几个程序都是在同一个处理机上运行.但在任一个时刻点只有一个程序在处理机上运行 并行: 在同一个时刻,多核处理多个任务 ...

  3. Parallel并行之乱用

    关于Parallel我也不细说了,一则微软封装的很好用,二来介绍这个的遍地都是. 我要说的是,要想成为一个优秀的标题党,一定要把重点放到别的地方,为了节省大家阅读时间,我先把结论说了,然后再慢慢从头说 ...

  4. 代码的坏味道(12)——平行继承体系(Parallel Inheritance Hierarchies)

    坏味道--平行继承体系(Parallel Inheritance Hierarchies) 平行继承体系(Parallel Inheritance Hierarchies) 其实是 霰弹式修改(Sho ...

  5. 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel)

    Task - 基于线程池的任务(在 System.Threading.Tasks 命名空间下) 多 Task 的并行执行 Parallel - 并行计算(在 System.Threading.Task ...

  6. Parallel.Foreach

    随着多核时代的到来,并行开发越来越展示出它的强大威力! 使用并行程序,充分的利用系统资源,提高程序的性能.在.net 4.0中,微软给我们提供了一个新的命名空间:System.Threading.Ta ...

  7. 在Parallel中使用DbSet.Add()发现的一系列多线程问题和解决过程

    发现问题 需求很简单,大致就是要批量往数据库写数据,于是打算用Parallel并行的方式写入,希望能利用计算机多核特性加快程序执行速度.想的很美好,于是快速撸了类似下面的一串代码: using (va ...

  8. Intel.parallel.studio.xe.2015.Update.2.ISO-TBE 下载

    磁力链下载点我 还有linux版本 Intel.parallel.studio.xe.2015.Update.1.LINUX.ISO-TBE 收集自网络,要跨请跨原作者,谢谢.

  9. Parallel并行编程初步

    Parallel并行编程可以让我们使用极致的使用CPU.并行编程与多线程编程不同,多线程编程无论怎样开启线程,也是在同一个CPU上切换时间片.而并行编程则是多CPU核心同时工作.耗时的CPU计算操作选 ...

  10. C#~异步编程再续~大叔所理解的并行编程(Task&Parallel)

    返回目录 并行这个概念出自.net4.5,它被封装在System.Threading.Tasks命名空间里,主要提供一些线程,异步的方法,或者说它是对之前Thread进行的二次封装,为的是让开发人员更 ...

随机推荐

  1. 第一个hello word 驱动载入失败--------

    今天尝试自己载入第一个驱动模块,依据惯例hello word 然后失败了,如今说明我的操作过程.请个位看看. 首先我的内核版本号: 模块代码与MAKEFILE #include<linux/in ...

  2. windows版 nginx配置反向代理实例教程 跳转tomcat和php网站

    抄自 https://www.cnblogs.com/j-star/p/8785334.html 个人理解 nginx端口设置为80,简称n tomcat端口设置为其他,例如8080,简称t php网 ...

  3. [Debug] Chrome Devtools: Elements - Console Integration

    The Element Inspector in Chrome DevTools offers powerful integration with the console - learn how to ...

  4. Nginx和Nginx+的比較(下)

    Nginx和Nginx+的比較(下) 作者:chszs.未经博主同意不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs 内容紧接上一篇<Nginx和 ...

  5. 幻灯展示jQuery插件supersized

    主要特性: 能够自动修改图片大小适合浏览器的页面大小 通过幻灯展示的循环背景可以动态加载并且可以设置变化方式 核心版本可以支持仅仅需要背景变化大小的需要 键盘导航 整合Flickr - 可以从用户,组 ...

  6. hadoop调优之一:概述 分类: A1_HADOOP B3_LINUX 2015-03-13 20:51 395人阅读 评论(0) 收藏

    hadoop集群性能低下的常见原因 (一)硬件环境 1.CPU/内存不足,或未充分利用 2.网络原因 3.磁盘原因 (二)map任务原因 1.输入文件中小文件过多,导致多次启动和停止JVM进程.可以设 ...

  7. 项目中使用Prism框架

    Prism框架在项目中使用   回顾 上一篇,我们介绍了关于控件模板的用法,本节我们将继续说明WPF更加实用的内容,在大型的项目中如何使用Prism框架,并给予Prism框架来构建基础的应用框架,并且 ...

  8. 【转】移动Web开发-点击事件及页面滚动

    点击事件 移动端浏览器点击事件默认有300ms的延迟 移动端实现弹性滚动 安卓局部滚动 滚动条出现bug,解决方案:Android只是用全局滚动 模拟全局滚动,加上padding-top及paddin ...

  9. POJ 1751 Highways (ZOJ 2048 ) MST

    http://poj.org/problem?id=1751 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2048 题目大 ...

  10. Call to a member function assign() on a non-object;thinkphp中报错

    这个在自己写的类中 需要function __construct(){parent::__construct();}继承父类构造函数 当发生这个错误的时候,需要在构造函数中集成父类构造