前段时间看到园子里面有同学在用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)上面运行测试,数据如下:

最新文章

  1. 分享几个.NET WinForm开源组件,纪念逐渐远去的WinForm。。。
  2. 【推荐】MySQL Cluster报错及解决方法(不断更新中)
  3. hibernate查询语句实例代码
  4. &ldquo;耐撕&rdquo;团队2016.03.28 站立会议
  5. swing LayoutManager 和多态
  6. SQL---------表的约束
  7. .NET之美——.Net 项目代码风格要求
  8. ASP.NET MVC 4 批量上传文件
  9. HttpWebRequest
  10. 零基Github Page个人博客建立教程无限的自由流动
  11. 深度-first遍历图--邻接表实现
  12. C语言 动态创建二维数组
  13. asp.net core mvc剖析:处理管道构建
  14. pgsql 递归查询 分页
  15. Angular和Spring Boot一起做个项目
  16. Linux的内核和权限
  17. partial 的随笔
  18. 运维利器万能的 strace
  19. python3 面向对象编程--类的封装和继承
  20. 比jsonpath 更方便的json 数据查询JMESPath 使用

热门文章

  1. 部分城市关于.Net招聘数量
  2. 自己定义View——坑、技巧、调优
  3. 用FATFS在SD卡里写一串数字
  4. 二次封装CoreData
  5. ios开发清除SDWebImage图片缓存
  6. php生成唯一字符串
  7. 群晖synology的Video Station无法通过浏览器在线播放视频
  8. ajax跳转到新的jsp页面(局部刷新)
  9. [CSS] Build Responsive CSS Layouts with Tachyons
  10. [TypeScript] Create a fluent API using TypeScript classes