【狼窝乀野狼】Parallel浅尝辄止
前段时间看到园子里面有同学在用Parallel进行批量插入数据库。后面也有很多同学针对这一事件给出了自己的看法和见解。我在这里不评论内容的好坏,至少能将自己东西总结分享这个是要靠勇气和毅力。
闲话少说,我在最近看崔鹏飞的github的时候,发现他对这块也做了一定的总结,那么我就他这块进行板书与展示。案例是怎么回事呢?话说我有一个公司,里面需要统计一下总收入,另外有一个公司被我收购了,我一起计算总收入。当一天我收购了N个公司,计算总收入的时候,我们采用并行计算。
internal class Company
{
public decimal TotalIncome; public Company Merge(Company that)
{
Calc();
TotalIncome += that.TotalIncome;
return this;
} /// <summary>
/// 复杂运算
/// </summary>
private void Calc()
{
//TODO:省略500字
}
}
首先我们想到的是采用直接累加就行了吧,这是所谓的线性预算。
/// <summary>
/// 线性运行
/// </summary>
/// <param name="bigCompany"></param>
/// <param name="smallCompanies"></param>
/// <returns></returns>
private static Company LinearMerge(Company bigCompany, IEnumerable<Company> smallCompanies)
{
foreach (Company smallCompany in smallCompanies)
{
bigCompany.Merge(smallCompany);
}
return bigCompany;
}
采用线性运算,毫无疑问结果是正确的。但是,如果的N大一点,例如30000000个,可能就要花一点时间了。
那么是否我们可以采用并行处理呢?OK,直接上代码。
/// <summary>
/// 并行处理
/// </summary>
/// <param name="bigCompany"></param>
/// <param name="smallCompanies"></param>
/// <returns></returns>
private static Company ParallelMerge(Company bigCompany, IEnumerable<Company> smallCompanies)
{
Parallel.ForEach(smallCompanies, smallCompany => bigCompany.Merge(smallCompany));
return bigCompany;
}
时间很快,但是结果呢?结果和上面线性的一致么?
那么我如果在并行的基础上面加一把锁呢,保证每次独占资源。
/// <summary>
/// 并行加锁
/// </summary>
/// <param name="bigCompany"></param>
/// <param name="smallCompanies"></param>
/// <returns></returns>
private static Company ParallelMergeLock(Company bigCompany, IEnumerable<Company> smallCompanies)
{
var obj = new object();
Parallel.ForEach(smallCompanies, smallCompany =>
{
lock (obj)
{
bigCompany.Merge(smallCompany);
}
});
return bigCompany;
}
毫无疑问,结果也是正确的,那么耗时可能我们就要关心了。那么耗时究竟怎么样呢?
我们可以采用函数式处理嘛。
/// <summary>
/// 函数式合并
/// </summary>
/// <param name="bigCompany"></param>
/// <param name="smallCompanies"></param>
/// <returns></returns>
private static Company FunctionalMerger(Company bigCompany, IEnumerable<Company> smallCompanies)
{
return smallCompanies.Aggregate(bigCompany, (buyer, seller) => buyer.Merge(seller));
}
那么我们在在函数式的基础上面进行并行化处理呢?
/// <summary>
/// 函数式的并行化
/// </summary>
/// <param name="bigCompany"></param>
/// <param name="smallCompanies"></param>
/// <returns></returns>
private static Company FunctionParallelMerge(Company bigCompany, IEnumerable<Company> smallCompanies)
{
return smallCompanies.AsParallel().Aggregate(() => new Company(), (shell, smallCompany) => shell.Merge(smallCompany), (shell1, shell2) => shell1.Merge(shell2), bigCompany.Merge);
}
上面提出了一些问题,这里我们用实际的测试数据查看。
测试代码
private static IEnumerable<Company> GenerateSmallCompanies()
{
return Enumerable.Range(, ).Select(number => new Company { TotalIncome = number }).ToArray();
} private static void PrintMergeResult(Func<Company, IEnumerable<Company>, Company> mergeMethod, string funcApproach)
{
var stopWatch = new Stopwatch();
stopWatch.Start();
var mergeResult = mergeMethod(new Company { TotalIncome = }, m_SmallCompanies);
stopWatch.Stop();
Console.WriteLine("{0}:{1} Time:{2}", funcApproach, mergeResult.TotalIncome, stopWatch.ElapsedMilliseconds);
} private static void TryAll()
{
Console.WriteLine("============================");
PrintMergeResult(LinearMerge, "简单直接 ");
PrintMergeResult(ParallelMerge, "错误并行 ");
PrintMergeResult(ParallelMergeLock, "加锁并行 ");
Console.WriteLine("***********");
PrintMergeResult(FunctionalMerge,"函数式合并 ");
PrintMergeResult(FunctionParallelMerge, "函数式并行合并 ");
} private static readonly IEnumerable<Company> m_SmallCompanies = GenerateSmallCompanies();
static void Main()
{
Console.WriteLine("测试数据30000000个");
for (int i = ; i < ; i++)
{
TryAll();
}
Console.ReadKey();
}
测试结果如下:

按照理论情况,错误并行应该比直接更快,但是不知道我机器(CPU AMD)上面出现这样的情况,其他情况还算正常。在另一台计算机(CPU Intel)上面运行测试,数据如下:

【狼窝乀野狼】Parallel浅尝辄止的更多相关文章
- 【狼窝乀野狼】Serializer妙手回春
在我们很多程序中,需要将数据保存到本地,以便于下次打开还能看到原始数据.例如我们Xmind思维导图,例如我们的Power Designer等等,都是有保存一个隶属于自己的工程文件,那么今天我要说的就是 ...
- 【狼窝乀野狼】Excel那些事儿
在工作中我们常常遇到Excel表格,不管是数据的导入导出,还是财务统计什么都,都离不开Excel,Excel是我见过的最牛逼的一个软件(可能我的见识少)没有之一:如果你只停留在Excel处理数据,统计 ...
- 【狼窝乀野狼】Windows Server 2008 R 配置 Microsoft Server 2008 远程登录连接
如果你已经了解了,或者你已经经历了,那么此篇文章对你是毫无用处.因为文笔深处未必有自己亲身体验来的真实有效. 闲话少说,直接上菜. 最近脑子“抽筋”,想安装一个服务器来玩玩,那么怎么选择呢?我的PC是 ...
- .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 ...
随机推荐
- VS2012调试C++工程DLL
1.C++工程属性对话框 2.配置属性: (1)常规:输出目录:..\Bin\WFCrawler(调用DLL的工程) 中间目录:..\Bin\WFCrawler(调用DLL的工程 ...
- js进阶 11-22/23 js如何实现选项卡
js进阶 11-22/23 js如何实现选项卡 一.总结 一句话总结:通过索引把选项卡头的li标签和选项卡内容的div标签联系在一起,通过控制div标签的display属性可以实现选项卡的选项切换. ...
- 细说document.ready和window.onload
原文 简书原文:https://www.jianshu.com/p/bbf28d61aa1f 大纲 1.对页面加载的认识 2.关于document.ready() 3.关于document.onloa ...
- Android 各个版本号WebView
转载请注明出处 http://blog.csdn.net/typename/ powered by miechal zhao : miechalzhao@gmail.com 前言: 依据Googl ...
- BZOJ 1695 [Usaco2007 Demo]Walk the Talk 链表+数学
题意:链接 方法:乱搞 解析: 出这道题的人存心报复社会. 首先这个单词表-先上网上找这个单词表- 反正总共2265个单词.然后就考虑怎么做即可了. 刚開始我没看表,找不到怎么做,最快的方法我也仅仅是 ...
- 360随身WIFI作USB无线网卡的做法
作者:朱金灿 来源:http://blog.csdn.net/clever101 1. 到控制面板上把360wifi卸载. 2. 到雷凌的官网下载网卡驱动,注意选择USB(RT2870***),操作系 ...
- Distribution download cancelled. Using distribution from 'https://services.gradle.org/distributions/
Distribution download cancelled. Using distribution from ‘https://services.gradle.org/distributions/ ...
- 【t062】最厉害的机器人
Time Limit: 1 second Memory Limit: 128 MB [问题描述] [背景] Wind设计了很多机器人.但是它们都认为自己是最强的,于是,一场比赛开始了~ [问题描述] ...
- Dubbo服务框架解析(二)
本节介绍dubbo-common,dubbo-common是公共逻辑模块,包含Util类.通用模型,是其他模块的基础. 扩展机制 SPI SPI是扩展点的注解.标注在类型上.全部的扩展点须要通过SPI ...
- 在向server发送请求时发生传输级错误。 (provider: 共享内存提供程序, error: 0 - 管道的还有一端上无不论什么进程。
作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/36425825 SQL Server 2008 + VS2010 用C#编写的代 ...