Chinaunix首页 | 论坛 | 博客
  • 博客访问: 192832
  • 博文数量: 90
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 0
  • 用 户 组: 普通用户
  • 注册时间: 2017-08-23 16:48
文章分类

全部博文(90)

文章存档

2015年(1)

2011年(21)

2010年(59)

2009年(9)

我的朋友

分类: C/C++

2010-06-17 13:55:14

本文以 Visual Studio 工具的预发布版为基础。文中的所有信息均有可能发生变更。
 
本文将介绍以下内容:
  • 并行计算
  • 并发编程
  • 性能提高
本文使用了以下技术:
多线程
 

从 1986到 2002 年,微处理器的性能每年提高了 52%。这一惊人的技术进步源自晶体管成本依据摩尔法则不断地缩减,以及处理器厂商在工程方面的出色表现。微软的研究员 Jim Larus 将上述两种因素的组合称为“摩尔红利”,他解释了这一红利如何造就了现代软件业并使计算机得以广泛普及(请参阅 )。

从软件方面讲,这一现象称为“免费的午餐”—只需升级运行应用程序的硬件就能改进其性能。(有关这方面的详细信息,请参阅“面向软件并发的基本转变”,网址为 。)

但如今的模式正在发生改变,处理器的增加使性能得到了改进。多核系统现在已是无处不在了。当然,只有软件能同时执行多个任务,多核方式才能提高性能。如果想让多处理器实现多处理器计算机所承诺的性能提高,必须编写可以使用顺序技术出色完成任务的函数。

并发和并行

现在,程序员有时必须要考虑并行给编程所带来的难题—并发。为了保证响应,需要有某种方式能从输入事件的处理线程卸载响应时间过长的活动。过去这类活动大部分涉及文件 I/O,但现在更多的是涉及与 Web 服务的会话。

Microsoft .NET Framework 提供了异步编程模型和后台工作程序理念,以适应这一常用编程需要。虽然在并行编程中平行编程的复杂性大部分相雷同,但基本模式和目标却各异。多核处理器不会减少并发编程需求,这种技术是用于优化后台活动和系统中的其它计算,目的是提高性能。

另一种常见的并发应用于服务器应用程序。Web 服务器这类应用程序会收到独立请求形成的流。.这些程序力求通过同时执行多项请求来改进系统的吞吐量,通常是对每个请求使用一个单独的线程,但依次处理每个请求。这种重叠可以增加每秒处理的请求数量,但对单个请求的延迟(每个请求所用的时间)并无裨益。
这些应用程序也在享受免费午餐,并且由于多核处理在成本和吞吐量方面具备优势,受益时间会更长。但是,任何对延迟敏感的请求(即使是在服务器环境中)最终还是需要使用并行编程技术来取得适合的性能。
并发编程对专家而言都是十分挠头的。如果逻辑上独立的请求共享多种资源(目录、缓冲池、数据库连接等),程序员必须构建共享,这会带来新的问题。这些问题(数据争用、死锁、活锁等)通常是由各种不确定性所造成的,当多项并发任务试图操控程序中的同一对象时,就会出现这些不确定性。它们会为测试和调试软件带来极大的困难,如 Rahul Patil 和 Boby George 近期在“识别并发问题的工具和方法”一文中所述(MSDN 杂志,2008 年 6 月,)。
并行编程与并发编程的区别在于您必须接受逻辑上的单一任务(可使用所有主要语言所支持的常用顺序结构表达)并为并发执行创造机会。(在本文后面的内容中,我将介绍实现这类机会的诸多途径。)但是,如果通过共享数据对象的子任务引入并发机会,必须要注意锁定和争用问题。因此,并行编程不但要面对顺序化程序所有的正确性和安全性难题,还要应对并行性和并发访问共享资源所带来的全部困难。
新的概念、新的失效模式和测试困难会让每个开发人员均望而却步。您确实真想领教一下它的厉害吗?当然不是!但是,很多时候为了能有必要的性能又不得不如此。Microsoft 正在积极开发应对此类问题的解决方案,但目前尚无效率很高的解决方案出台。

去年,Microsoft 发起了“平行计算管理计划”(),该活动不但是要探讨如何构建并有效执行并行程序,而且旨在鼓励创建新一代应用程序,能够将“摩尔红利”转化为客户价值。我将很快研讨一些并行性的思路。Stephen Toub 和 Hazim Shafi 在本期的文章“”介绍了一些我们用于支持这些方法的库和工具。Joe Duffy 在本期的文章“”中讨论了改进并发应用程序安全的技术和方法。

以前,我使用“并发执行机会”一词进一步区分并行与并发编程。如开发人员使用异步编程模式或后台工作程序,或者在服务器中处理并发请求,这里会有一个例外,即所有不同的线程一律前行。操作系统的任务计划程序将确保每个线程均获得公平的共享资源。但这一点对于并行编程并无帮助。如果您感兴趣的是编写将用于新硬件系统的应用程序,它能发挥的作用就更为有限。

如果您想从免费午餐中受益,即通过硬件升级使软件的性能更好,则需要让更多现有的并行功能可以在将来继续发挥功效。在此,我将使用“任务”这一术语取代线程,来强调并行实施中的转变以及我的思路:鼓励应对并行编程的开发人员将问题分解为更多的任务。

并行编程系统的实现应该能根据需要将这些任务映射给系统线程和处理器。只有为数不多的程序员发现,从操作系统取得系统资源并在进程中进行管理以便有效执行并行程序的方式有了巨大的变化。它就象一个线程池,但侧重于将应用程序中的并行机会与当前硬件的可用资源相搭配,而不只是按并行程序员的指令管理线程。

在并发编程中(尤其是服务器),大部分困难源自使用锁等工具协调长时间运行线程对共享变量的访问。如转为具备任务的并行编程,可以使用一个新概念。例如,在任务 A 后面运行一个任务 B,并提供基本协调元素对其加以说明。这样程序员就可以考虑为工作制订计划。通常,这一计划会从本质上配合程序的算法结构,并从并行编程抽象的结构化使用中反映出来。程序抽象与并行算法间的良好配合能极大地减少对传统并发机制的需求(如锁和事件),并可避免许多并发编程的风险(但不能完全消除)。

接下来,我将说明一些并行编程的主要方法并通过正在开发的抽象展示其使用。我还会特别使用 C# 展示 C++ 并行模式库 (PPL) 和 .NET 并行扩展(网址为 )。

结构化多线程

人们处理问题时最常用的模式是先分割再解决:使用定义良好的交互将一个大问题分解为多个小问题,这些问题可单独解决,然后将结果汇总,从而解决原始问题。无论是大型公司的风险,还是邻居的日常琐事,它们都使用这一技术解决问题。由这一观念带动的应用程序也顺理成章的成为了并行编程的基础。

结构化多线程指提供并行模式的顺序语句,它的块呈结构化。例如,一条采用顺序语法的复合语句 { A; B; },原本先求 A 的值,再求 B 的值,现在成为了一个并行语句,A 和 B 可以同时求值。但整个构造并未完成,控制继续转到下一个构造,直到两项子任务全部完成为止。这是一个旧概念,一直被视为 Cobegin 语句有时也称为“派生-联结并行性”以突出结构。相同的基本观点也适用于循环,其中每个迭代均定义一个任务,该任务与其他迭代同时计算。所有迭代均完成后,并行循环即告结束。

著名的 Qu

阅读(1966) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~