.NET并行编程实践(一:.NET并行计算基本介绍、并行循环使用模式)

阅读目录:

  • 1.开篇介绍
  • 2.NET并行计算基本介绍
  • 3.并行循环使用模式
    • 3.1并行For循环
    • 3.2并行ForEach循环
    • 3.3并行LINQ(PLINQ)

1】开篇介绍

最近这几天在捣鼓并行计算,发现还是有很多值得分享的意义,因为我们现在很多人对它的理解还是有点不准确,包括我自己也是这么觉得,所以整理一些文章分享给在使用.NET并行计算的朋友和将要使用.NET并行计算的朋友;

NET并行编程推出已经有一段时间了,在一些项目代码里也时不时会看见一些眼熟的并行计算代码,作为热爱技术的我们怎能视而不见呢,于是捣鼓了一番跟自己的理解恰恰相反,看似一段能提高处理速度的并行代码为能起效果,跟直接使用手动创建的后台线程处理差不多,这不太符合我们对.NET并行的强大技术的理解,所以自己搞了点资料看看,实践了一下,发现在使用.NET并行技术的时候需要注意一些细节,这些细节看代码是看不出来的,所以我们看到别人这么用我们就模仿这么用,我们需要自己去验证一下到底能提高多少处理速度和它的优势在哪里;要不然效率上不去反而还低下,查看代码也不能很好的断定哪里出了问题,所以还是需要系统的学习总结才行;

现在的系统已经不在是以前桌面程序了,也不是简单的WEB应用系统,而是大型的互联网社区、电子商务等大型系统,具有高并发,大数据、SOA这些相关特性的复杂体系的综合性开放平台;.NET作为市场占有率这么高的开发技术,有了一个很强大的并行处理技术,目的就是为了能在高并发的情况下提高处理效率,提高了单个并发的处理效率也就提高了总体的系统的吞吐量和并发数量,在单位时间内处理的数据量将提高不是一个系数两个系数;一个处理我们提高了两倍到三倍的时间,那么在并发1000万的顶峰时时不时很客观;

2】.NET并行计算基本介绍

既然是.NET并行计算,那么我们首先要弄清楚什么叫并行计算,与我们以前手动创建多线程的并行计算有何不同,好处在哪里;我们先来了解一下什么是并行计算,其实简单形容就是将一个大的任务分解成多个小任务,然后让这些小任务同时的进行处理,当然纯属自己个人理解,当然不是很全面,但是我们使用者来说足够了;

在以前单个CPU的情况下只能靠提高CPU的时钟频率,但是毕竟是有极限的,所以现在基本上是多核CPU,个人笔记本都已经基本上是4核了,服务器的话都快上20了;在这样一个有利的计算环境下,我们的程序在处理一个大的任务时为了提高处理速度需要手动的将它分解然后创建Thread来处理,在.NET中我们一般都会自己创建Thread来处理单个子任务,这大家都不陌生,但是我们面临的问题就是不能很好的把握创建Thread的个数和一些参数的控制,毕竟.NET并行也是基于以前的Thread来写的,如何在多线程之间控制参数,如何互斥的执行的线程顺序等等问题,导致我们不能很好的使用Thread,所以这个时候.NET并行框架为我们提供了一个很好的并行开发平台,毕竟大环境就是多核时代;

下面我们将接触.NET并行计算中的第一个使用模式,有很多并行计算场景,归结起来是一系列使用模式;

3】并行循环模式

并行循环模式就是将一个大的循环任务分解成多个同时并行执行的小循环,这个模式很实用;我们大部分处理程序的逻辑都是在循环和判断之间,并行循环模式可以适当的改善我们在操作大量循环逻辑的效率;

我们看一个简单的例子,看到底提升了多少CPU利用率和执行时间;

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Threading.Tasks;
 4 using System.Diagnostics;
 5
 6 namespace ConsoleApplication1.Data
 7 {
 8     public class DataOperation
 9     {
10         private static List<Order> orders = new List<Order>();
11
12         static DataOperation()
13         {
14             for (int i = 0; i < 9000000; i++)
15             {
16                 orders.Add(new Order() { Oid = Guid.NewGuid().ToString(), OName = "OrderName_" + i.ToString() });
17             }
18         }
19
20         public void Operation()
21         {
22             Console.WriteLine("Please write start keys:");
23             Console.ReadLine();
24
25             Stopwatch watch = new Stopwatch();
26             watch.Start();
27             orders.ForEach(order =>
28             {
29                 order.IsSubmit = true;
30                 int count = 0;
31                 for (int i = 0; i < 2000; i++)
32                 {
33                     count++;
34                 }
35             });
36             watch.Stop();
37             Console.WriteLine(watch.ElapsedMilliseconds);
38         }
39
40         public void TaskOperation()
41         {
42             Console.WriteLine("Please write start keys:");
43             Console.ReadLine();
44
45             Stopwatch watch = new Stopwatch();
46             watch.Start();
47             Parallel.ForEach(orders, order =>
48             {
49                 order.IsSubmit = true;
50                 int count = 0;
51                 for (int i = 0; i < 2000; i++)
52                 {
53                     count++;
54                 }
55             });
56             watch.Stop();
57             Console.WriteLine(watch.ElapsedMilliseconds);
58         }
59     }
60 } 

View Code

这里的代码其实很简单,在静态构造函数中我初始化了九百万条测试数据,其实就是Order类型的实例,这在我们实际应用中也很常见,只不过不是一次性的读取这么多数据而已,但是处理的方式基本上差不多的;然后有两个方法,一个是Operation,一个是TaskOperation,前者顺序执行,后者并行执行;

在循环的内部我加上了一个2000的简单空循环逻辑,为什么要这么做后面会解释介绍(小循环并行模式不会提升性能反而会降低性能);这里是为了让模拟场景更真实一点;

我们来看一下测试相关的数据:i5、4核测试环境,执行时间为42449毫秒,CPU使用率为25%左右,4核中只使用了1和3的,而其他的都属于一般处理状态;

图1:

我们再来看一下使用并行计算后的相关数据:i5、4核测试环境,执行时间为19927毫秒,CPU利用率为100%,4核中全部到达顶峰;

图2:

这一个简单的测试例子,当然我只测试了两三组数据,基本上并行计算的速度要快于单线程的处理速度的2.1倍以上,当然还有其他因素在里面这里就不仔细分析了,起到抛砖引玉的作用;

3.1】并行For循环

在使用for循环的时候有相应的Parallel方式使用for循环,我们直接看一下示例代码,还是以上面的测试数据为例;

1 Parallel.For(0, orders.Count, index =>
2             {
3                 //
4             }); 

View Code

第一个参数是索引的开始,第二个参数是循环总数,第三个是执行体,参数是索引值;使用起来其实很简单的;

3.2】并行ForEach循环

同样ForEach也是很简单的,还是使用上面的测试数据为例;

1 Parallel.ForEach(orders, order =>
2             {
3                 order.IsSubmit = true;
4                 int count = 0;
5                 for (int i = 0; i < 2000; i++)
6                 {
7                     count++;
8                 }
9             }); 

View Code

在Parallel类中有ForEach方法,第一个参数是迭代集合,第二个是每次迭代的item;

其实Parallel为我们封装了一个简单的调用入口,其实是依附于后台的Task框架的,因为我们常用的就是循环比较多,毕竟循环是任务的入口调用,所以我们使用并行循环的时候还是很方便的;

3.3】并行LINQ(PLINQ)

首先PLINQ是只针对Linq to Object的,所以不要误以为它也可以使用于Linq to Provider,当然自己可以适当的封装;现在LINQ的使用率已经很高了,我们在做对象相关的操作时基本上都在使用LINQ,很方便,特别是Select、Where非常的常用,所以.NET并行循环也在LINQ上进行了一个封装,让我们使用LINQ的时候很简单的使用并行特性;

LINQ核心原理的文章:http://www.cnblogs.com/wangiqngpei557/category/421145.html

根据LINQ的相关原理,知道LINQ是一堆扩展方法的链式调用,PLINQ就是扩展方法的集合,位于System.Linq.ParallelEnumerable静态类中,扩展于ParallelQuery<TSource>泛型类;

System.Linq.ParallelQuery<TSource>:

 1 using System.Collections;
 2 using System.Collections.Generic;
 3
 4 namespace System.Linq
 5 {
 6     // 摘要:
 7     //     表示并行序列。
 8     //
 9     // 类型参数:
10     //   TSource:
11     //     源序列中的元素的类型。
12     public class ParallelQuery<TSource> : ParallelQuery, IEnumerable<TSource>, IEnumerable
13     {
14         // 摘要:
15         //     返回循环访问序列的枚举数。
16         //
17         // 返回结果:
18         //     循环访问序列的枚举数。
19         public virtual IEnumerator<TSource> GetEnumerator();
20     }
21 } 

View Code

System.Linq.ParallelEnumerable:

1 // 摘要:
2     //     提供一组用于查询实现 ParallelQuery{TSource} 的对象的方法。 这是 System.Linq.Enumerable 的并行等效项。
3     public static class ParallelEnumerable {}

View Code

我们在用的时候只需要将它原本的类型转换成ParallelQuery<TSource>类型就行了;

1 var items = from item in orders.AsParallel() where item.OName.Contains("1") select item;

View Code

Linq 的扩展性真的很方便,可以随意的封装任何跟查询相关的接口;

 

作者:王清培

出处:http://www.cnblogs.com/wangiqngpei557/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

时间: 2024-08-02 01:55:12

.NET并行编程实践(一:.NET并行计算基本介绍、并行循环使用模式)的相关文章

《深入理解并行编程》中文版

原文的下载地址:http://kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html 中文版下载地址:深入理解并行编程V1.0 (4.1M) 本书是linux内核大牛paul的力作,和鲁阳同学一起,花了两个月时间进行翻译. 目前没有翻译问答部分,主要是时间不够,也担心不能将这部分翻译准确. 对内核深度发烧的同学可以看看. 本书目录 1. 简介----------------------------------- 14 1

《深入理解大数据:大数据处理与编程实践》一一1.3 MapReduce并行计算技术简介

1.3 MapReduce并行计算技术简介 1.3.1 MapReduce的基本概念和由来 1.?什么是MapReduce MapReduce是面向大数据并行处理的计算模型.框架和平台,它隐含了以下三层含义: 1)MapReduce是一个基于集群的高性能并行计算平台(Cluster Infrastructure).它允许用市场上普通的商用服务器构成一个包含数十.数百至数千个节点的分布和并行计算集群. 2)MapReduce是一个并行计算与运行软件框架(Software Framework).它提

《OpenACC并行程序设计:性能优化实践指南》一 第1章 从串行编程到并行编程

第1章 从串行编程到并行编程 Rob Farber TechEnablement.com CEO/创始人 本章主要向读者介绍OpenACC,演示如何使用OpenACC编写运行在多核CPU和类似GPU加速器上的可移植并行程序,并展示如何在CPU和GPU上编译和运行OpenACC程序. 阅读本章后,读者将会理解以下内容: 如何创建.编译和运行OpenACC应用程序. 高性能OpenACC编程的三个准则. 数据并行和任务并行编程的基本概念. 理解大O表示法和Amdahl定律. 竞争条件.原子操作,以及

用Hadoop进行分布式并行编程, 第1部分

Hadoop 是一个实现了 MapReduce 计算模型的开源分布式并行编程框架,借助于 Hadoop, 程序员可以轻松地编写分布式并行程序,将其运行于计算机集群上,完成海量数 据的计算.本文将介绍 MapReduce 计算模型,分布式并行计算等基本概念,以及 Hadoop 的安装部署和基本运行方法. Hadoop 简介 Hadoop 是一个开源的可运行于大规模集群上的分布式并行编程框架,由于分布式存储 对于分布式编程来说是必不可少的,这个框架中还包含了一个分布式文件系统 HDFS( Hadoo

模式转变:并行编程方面的设计注意事项

本文以 Visual Studio 工具的预发布版为基础.文中的所有信息均有可能发生变更. 本文将介绍以下内容: 并行计算 并发编程 性能提高 本文使用了以下技术: 多线程 从 1986到 2002 年,微处理器的性能每年提高了 52%.这一惊人的技术进步源自晶体管成本依据摩尔 法则不断地缩减,以及处理器厂商在工程方面的出色表现.微软的研究员 Jim Larus 将上述两种因素的 组合称为"摩尔红利",他解释了这一红利如何造就了现代软件业并使计算机得以广泛普及(请参阅 go.micro

Akka入门编程实践

Akka是使用Scala语言开发一个编程库,基于事件驱动的架构实现异步处理,它能够简化编写分布式应用程序.Akka中最核心的概念是Actor模型,它为编写分布式/并行计算应用程序提供了高层次抽象,在实际编程实践中,开发人员可以从对复杂网络通信细节的处理.多线程应用场景下对锁的管理中解脱出来. Akka能够给应用程序带来的几个重要的特性是: 容错性 可伸缩性 异步性 事件驱动架构(EDA) 远程透明性 Actor是Akka中最核心的组件,以至于我们在编写基于Akka的应用程序时,大部分时间都会和A

深入理解并行编程-锁

锁 在过去几十年并发研究领域的出版物中,锁总是扮演着坏人的角色,锁背负的指控包括引起死锁.锁封护(luyang注:lock convoying,多个同优先级的线程重复竞争同一把锁,此时大量虽然被唤醒而得不到锁的线程被迫进行调度切换,这种频繁的调度切换相当影响系统性能).饥饿.不公平.data races以及其他许多并发带来的罪孽.有趣的是,在共享内存并行软件中真正承担重担的是--你猜对了--锁. 图1.1:锁:坏人还是懒汉? 这种截然不同的看法源于下面几个原因: 1. 很多因锁产生的问题大都有实

C#并行编程-相关概念

原文:C#并行编程-相关概念 菜鸟初步学习,不对的地方请大神指教,参考<C#并行编程高级教程.pdf> 背景 当今计算机至少都有一颗双核的微处理器,带有四核.八核的计算机非常常见,在单个处理器上具有多个内核的时代正在来临,现代微处理器提供了新型的多核架构,因此软件设计和编码能够充分发挥这些架构的功能是非常重要的事情,也要与时俱进. 多核微处理器 多核微处理器有很多种不同的复杂微架构,意在提供更强的并行执行能力,提升吞吐量,减少潜在的性能瓶颈,缩减电源消耗,并减少发热量,因此,现代很多的微处理器

《OpenACC并行编程实战》—— 1.2 并行编程语言

1.2 并行编程语言 在并行计算发展史上出现过多种并行编程语言,至今仍在使用的只剩几种, 它们各有特色. (1)Pthreads 20世纪70年代,贝尔实验室发明了UNIX,并于20世纪80年代向美国各大高校分发V7版的源码以做研究.加利福尼亚大学伯克利分校在V7的基础上开发了BSD UNIX.后来很多商业厂家意识到UNIX的价值也纷纷以贝尔实验室的System V或BSD为基础来开发自己的UNIX,较著名的有Sun OS.AIX.VMS.随着操作系统的增多,应用程序的适配性工作越来越繁重.为了