- 浏览: 13970 次
最新评论
并行 .net 应用程序的过去、现在和未来
- 博客分类:
- 技术杂绘
并行 .net 应用程序的过去、现在和未来
2011年08月31日
以往,开发人员在尝试实现响应及时的客户端应用程序、并行算法和可伸缩服务器时,一直都采用直接线程操作。 然而,这类方法也一直为开发人员制造着麻烦,比如死锁、活锁、锁保护、两步舞曲、争用条件、过度订阅和应用程序中的许多其他缺陷。 从诞生之初,Microsoft .NET Framework 便提供了大量较低级别的工具,用于构建并发应用程序,包括专为这项工作提供的整个命名空间:System.Threading。 借助 .NET Framework 3.5 核心程序集在此命名空间中提供的大约 50 种类型(包括 Thread、ThreadPool、Timer、Monitor、ManualResetEvent、ReaderWriterLock 和 Interlocked 等类型),人们不应责怪 .NET Framework 的线程支持太少。 不过,在我看来,.NET Framework 的以往版本对开发人员提供的真正支持仍有欠缺,不足以让他们在任何位置都能成功构建可伸缩且高度并行化的应用程序。 我十分欣慰和兴奋地告诉大家,这个问题在 .NET Framework 4 中得到了纠正,并且对未来 .NET Framework 版本会继续有大量投资。
有些人可能会质疑托管语言中的丰富子系统对于编写并行代码的价值。 毕竟,并行性和并发性关乎性能,而注重性能的开发人员应寻求本机语言,因为这些语言可提供对硬件的充分访问以及对每个位调整、缓存行操作和联锁操作的完全控制… 对吧? 如果情况确实如此,我会为我们行业的现状感到担忧。 托管语言(如 C#、Visual Basic 和 F#)的存在是为了向所有开发人员 ― 无论是无名小卒还是超级英雄 ― 提供一个安全且富有成效的环境,用于快速开发强大而高效的代码。 开发人员有成千上万的预生成库类可供使用,还有包含我们所期待的所有先进服务的成熟语言,并且仍设法在几乎最繁重的数字处理和浮点密集型工作负载下实现卓越的性能。 所有这些意味着,托管语言及其关联框架针对构建高性能并发应用程序提供了深层支持,使得使用最新硬件的开发人员也可以从中受益。
我一直认为模式学习是一种很好的学习方法,因此对于当前的主题,我们最好也通过了解一种模式来开始我们的探索。 无论是“进退两难的并行”还是“令人愉快的并行”模式,最常需要的一种“派生-联结”构造都是并行循环,该循环旨在并行处理循环中的每个独立迭代。 了解如何使用前面提到的较低级别基元进行这类处理颇具指导意义,为此我们将演练一下使用 C# 实现的简单并行循环的基本实现。 考虑下面的典型 for 循环:
for (int i=0; i线程直接实现此循环的并行化,如图 1 所示。
图 1 并行化 For 循环
int lowerBound = 0, upperBound = N;int numThreads = Environment.ProcessorCount;int chunkSize = (upperBound - lowerBound) / numThreads; var threads = new Thread[numThreads];for (int t = 0; t 新线程,这不仅会增加开销(特别是循环主体在待完成工作中非常琐细时),而且还可能会导致在同时进行其他工作的进程中出现严重的过度订阅。 我们使用静态分区在线程间划分工作,如果工作负载在迭代空间中分布不均匀,则可能会导致严重的负载不平衡(更不用提迭代数目不能由所用线程数均匀分割,导致最后一个线程承受溢出的情况)。 然而,最糟糕的可能是开发人员可能一开始便被强迫编写此代码。 我们尝试并行化的每个算法都需要类似的代码(十分脆弱的代码)。
当我们认识到并行循环只是并行程序中存在的众多模式中的一个模式时,会进一步放大通过上面代码举例说明的问题。 强迫开发人员以此低级别编码表示所有这类并行模式不会形成良好的编程模型,不会让世界上需要利用高度并行硬件的众多开发人员取得成功。
并行编程的现在让我们进入 .NET Framework 4。 此版本 .NET Framework 扩充了大量功能,显著降低了开发人员在应用程序中表示并行性的难度,并提高了并行执行的效率。 这远远超出了并行循环的范畴,尽管如此,我们仍将从这里开始。
System.Threading 命名空间在 .NET Framework 4 中通过一个新的子命名空间得到了增强:System.Threading.Tasks。 此命名空间包含一个新类型 Parallel,该类型公开了丰富的静态方法,用以实现并行循环和结构化“派生-联结”模式。 作为其用法的示例,请考虑前面的 for 循环:
for (int i=0; i { ... // Process i here});
在这里,开发人员仍负责确保循环的每个迭代实际上都是独立的,但除此之外,Parallel.For 构造会处理此循环的并行化的所有方面。 该构造跨计算中涉及的所有基础线程动态地对输入范围进行分区,同时仍尽可能减小分区的开销,使其接近于静态分区实现的开销。 该构造动态地增加和减少计算中涉及的线程数,以便发现最适合给定工作负载的最佳线程数(与惯常认知不同的是,最佳线程数并不总是等于硬件线程数)。 该构造还提供前面演示的简单实现中不存在的异常处理功能,等等。 最重要的是,该构造使开发人员不必在线程的较低级别操作系统抽象层考虑并行性,并且无需为工作负载分区、卸载到多个核心以及高效地联接结果而一次又一次地编写谨小慎微的解决方案。 如此,开发人员便可集中时间处理更重要的工作:使开发人员的工作更富收益的业务逻辑。
Parallel.For 还为需要更加精细地控制循环操作的开发人员提供了便利工具。 通过为 For 方法提供的一个选项包,开发人员可以控制循环运行所在的基础计划程序、要使用的最大并行度,以及循环外部实体用于请求在循环方便时尽早正常终止的取消标记:
var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };Parallel.For(0, N, options, i=> { ... // Process i here});
此自定义功能突出了 .NET Framework 中此并行化工作的一个目标:在不使编程复杂化的情况下显著降低开发人员利用并行性的难度,同时为更加高级的开发人员提供了对处理和执行进行微调所需的工具。 出于此目的,还支持其他调整。 Parallel.For 的其他重载使开发人员可以尽早中断循环:
Parallel.For(0, N, (i,loop) => { ... // Process i here if (SomeCondition()) loop.Break();});
还有其他重载使开发人员能够使状态流过最终在同一基础线程上运行的迭代,从而显著提高算法实现(如缩减)的效率,例如:
static int SumComputations(int [] inputs, Func computeFunc) { int total = 0; Parallel.For(0, inputs.Length, () => 0, (i,loop,partial)=> { return partial + computeFunc(inputs); }, partial => Interlocked.Add(ref total, partial));}
Parallel 类不仅为整数范围提供支持,还为任意 IEnumerable 源(可枚举序列的 .NET Framework 表示形式)提供支持:代码可以对枚举器连续地调用 MoveNext,以便检索下一个 Current 值。 通过这种使用任意可枚举内容的能力可实现任意数据集的并行处理,而无论数据在内存中的表示形式如何;数据源甚至可以根据需要具体化,并在 MoveNext 调用到达源数据的尚未具体化部分时分页:
IEnumerable lines = File.ReadLines("data.txt");Parallel.ForEach(lines, line => { ... // Process line here});
与 Parallel.For 一样,Parallel.ForEach 也采用许多自定义功能,但提供比 Parallel.For 更大的控制能力。 例如,ForEach 使开发人员可以自定义对输入数据集进行分区的方式。 这通过一组侧重于分区的抽象类完成,这些抽象类使并行化构造可以请求固定或可变数量的分区,从而允许分区程序将这些分区抽象分派给输入数据集,并根据需要以静态或动态方式将数据分配给这些分区:
Graph graph = ...;Partitioner data = new GraphPartitioner(graph);Parallel.ForEach(data, vertex => { ... // Process vertex here});
Parallel.For 和 Parallel.ForEach 在 Parallel 类上补充提供了一个 Invoke 方法,该方法接受任意数量的待调用操作,并可实现基础系统可以支持的最大并行度。 通过此经典的“派生-联结”构造可以轻松地并行化递归的“分割-解决”算法,如常用的 QuickSort 示例:
static void QuickSort(T [] data, int lower, int upper) { if (upper
发表评论
-
PHP作为Flex程序的数据源
2012-01-20 01:22 533PHP作为Flex程序的数据源 2010年10月20日 ... -
myeclipse6.5+flex 3 + tomcat6.0 + ds-console.war环境搭建
2012-01-20 01:22 1137myeclipse6.5+flex 3 + tomcat6.0 ... -
flex图表
2012-01-20 01:22 1349flex图表 2010年07月13日 flex 可视化组 ... -
flex笔记--安装与项目建立
2012-01-20 01:22 444flex笔记--安装与项目建立 2011年01月04日 ... -
使用blazeds实现flex和java交互
2012-01-20 01:22 593使用blazeds实现flex和java交互 2010年07 ... -
C#面试题集锦(你值得拥有!)
2012-01-19 09:13 850C#面试题集锦(你值得拥 ... -
ASP.Net考试复习资料
2012-01-19 09:13 1056ASP.Net考试复习资料 2011 ... -
javascript:history.go()和History.back()的区别
2012-01-19 09:12 1092javascript:history.go()和History ... -
多线程
2012-01-17 01:42 736多线程 2011年05月15日 ... -
Java NIO 异步网络构建高性能服务器
2012-01-17 01:42 950Java NIO 异步网络构建高性能服务器 2010年12月 ... -
超线程与同步多线程
2012-01-17 01:42 721超线程与同步多线程 20 ... -
43543254325432
2012-01-17 01:42 62843543254325432 2011年06月23日 ... -
关于cgi库
2012-01-15 20:56 796关于cgi库 2009年07月02日 目前Web技术中生 ... -
嵌入式WEB服务器BOA的移植方法(三)
2012-01-15 20:56 718嵌入式WEB服务器BOA的移 ... -
SAMSUNG S3C2440的简易BootLoader ㈢
2012-01-15 20:56 521SAMSUNG S3C2440的简易BootLoa ... -
linux C库函数(二)
2012-01-15 20:56 640linux C库函数(二) 2010年01月26日 li ... -
linux C库函数(三)
2012-01-15 20:56 671linux C库函数(三) 2010年0 ...
相关推荐
演示.NET控制台应用程序,可快速基准化并行与循环处理速度。 当前主要以Parallel.For()并行处理为特色,并且将来可能还会通过使用Tasks获益,此外,在文件系统上测试操作将是一个不错的选择。
批处理并行图像调整器使用并行处理的图像大小调整应用程序该应用程序最初是RedGate的免费电子书“提高.NET性能的52技巧与窍门”( )中的性能提示的示例实现。 在上的博客文章中,我详细介绍了该技术。 该应用程序的...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
Open Inventor是目前世界上应用最为广泛的面向对象和交互式的三维图形软件开发包。它是在OpenGL的基础上开发而成的,因而也是一种相对独立的图形系统,并可方便地移植到不同操作系统的硬件平台上。由于Open Inventor...
并行测试运行器 由Akka.NET支持的NUnit分布式测试运行程序。 目录 描述 ParallelTestRanner-创建的工具,用于添加使用Akka.NET并行运行的NUnit... 在打开的控制台应用程序窗口中,输入run tests.dll --localrun=2 。 这
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...
SignalR 是 ASP.NET 团队正在开发的一个 Microsoft .NET Framework 库和 jQuery 插件,可能包括在以后版本...我们可以看到未来网络应用中会大量出现自己吃WebSockets的程序,而SignalR应该也会广泛在ASP.NET 网站中出现
整个框架没有使用特有的脚本语言,普通程序员不需要再去学习相对陌生的语法或者函数,现在使用C#,未来会扩展到JAVA语言,不需要了解复杂的MR算法,只要知道Key集切分规则和原理,并行计算特点和一些注意事项就可以...
5.1.4 使用GNOME客户程序和工具 63 5.1.5 使用GNOME Control Center配置 桌面 64 5.1.6 GNOME面板配置 65 5.2 Enlightenment窗口管理器特性 67 5.3 K桌面环境特性 68 5.3.1 安装组件 68 5.3.2 使用kdm登录 68 5.3.3...
ModernUI(http://mui.codeplex.com/)是一个开源的WPF界面库,利用该界面库,我们可以创建很酷的应用程序。下面是ModernUI官方示例,你可以从官方网站直接下载源码运行,如果是.NET 4.0的话,记得要声明“NET4”预...
ModernUI(http://mui.codeplex.com/)是一个开源的WPF界面库,利用该界面库,我们可以创建很酷的应用程序。下面是ModernUI官方示例,你可以从官方网站直接下载源码运行,如果是.NET 4.0的话,记得要声明“NET4”预...