Welcome

首页 / 软件开发 / .NET编程技术 / 使用并发与协调运行时

使用并发与协调运行时2011-04-05 infoq 译者:赵劼介绍

并发与协调运行时(Concurrency and Coordination Runtime,CCR)是一个.NET平台 上的异步信息传递类库,提供了一套细小而强大的基础功能,能够使用不同的方式来组织 应用程序。应用程序通过有效使用CCR可以获得更好的响应能力,以及更好的伸缩性及容 错性。而它最神奇的地方则在于,开发人员获得这些便利的同时,还减少(甚至完全消除 )了对线程、锁、互斥体(mutex)或其他同步元素的直接操作(或捕获错误)。

如果您的应用程序是单线程的,CCR可以使您的程序提高响应能力,并且更充分利用 CPU核心——同时让您的代码库从概念上保持整洁。如果您的程序已经启用了多线程,那 么CCR能够在简化您代码库的同时,保持(甚至改进)程序的吞吐量。

简单说来,CCR提供了如下功能:

一个简单而高性能的消息传递实现。使用非常轻量级且类型安全的通道,以面向 Action的视角把各种对象连接了起来。

一套基础的调度约束。调度几乎就是CCR的全部。您可以创建各种任务,把消息传递给 进程中的其他组件,并且通过一些叫做仲裁器(Arbiter)的对象来声明一些约束,以此 对请求进行处理。在执行您的代码之前,CCR能够保证这些约束已经得到满足。

为失败处理提供了一种更好的模型。CCR提供了“Causality”,意味着为一系列相关 异步子任务提供一个上下文,这样某个任务失败时(例如抛出了异常),那么这样的失败 能在单独的地方进行隔离处理,这与发起任务的线程并没有关系。

更好的使用已有的(或将来会有的)计算能力。CCR能够使用现有的线程池进行调度, 如果您需要的话,也可以使用它自带的实现,这在某些情况下能够带来更好的性能。自然 ,这个机制只会对您的代码产生细微的影响。

使异步IO操作得以简化。提高独立进程的伸缩性与性能的关键,最终往往归结于高效 的I/O密集型操作。I/O密集型操作往往会比计算密集型操作要慢许多倍,而一个阻塞的 I/O操作会浪费有效的资源(在这里就是线程),使它们无法处理其他等待的任务。使用 异步的I/O操作能够释放这些资源,让它们去处理其他任务,直到I/O操作完成。然而,一 系列的异步操作需要将其“开始”及“完成”分开,这使编码难度变得很大。CCR使用特 别的C#迭代器实现,使开发人员能够轻松控制此类操作。

通过“异步消息传递”机制,我们的组件通过发送数据的方式与另一个组件进行通信 ,更值得一提的是,数据与后续回复没有确定的临时关系。一个已发送的消息可能需要在 未来某个时候才会得到处理,也只有到那个时候消息才会得到回复。

这种异步消息传递模型是大部分情况下跨进程(inter-process)计算的基础,不过与 之相比,在现实应用中使用CCR来进行纯粹的进程内部(intra-process)通信往往可以得 到更好的保证,不像前者在很多情况下都可能失败。因此,CCR不仅可以用于低级I/O操作 ,对于构建伸缩性强的分布式系统也可以提供很好的辅助。

CCR的基础类型

CCR由几种基础类型组成:

任务(Task):任意一段用于执行的代码。

任务队列(TaskQueue):确切地说,是“分发队列(DispatcherQueue)”。一个待 执行任务的列表。一个CLR线程池或CCR线程池(即Dispatcher)的线程会从队列中取出任 务并加以执行。

端口(Port):进程内部连接各组件的消息队列。简单来说这只是个链表(linked- list),生成者在端口内放置消息。CCR提供了泛型的重载,可以提供类型安全的操作。

仲裁器(Arbiters):CCR的基础元素,它们将端口和任务连接起来。它们定义了一些 约束,用于在消息到达端口后确定需要创建的任务,以及使用哪个任务队列进行接受。 CCR中内置了多种仲裁器,其中大部分可以进行组合,以此获得更灵活的功能。

了解了这些基本概念之后,我们来看一些简单的CCR代码。首先,我们来定义一个简单 的C#控制台应用程序,它会用来运行所有的示例。注意在这个程序中,我们使用了CCR自 定义的线程池(Dispatcher)并与我们的任务队列绑定。这意味着队列中任务会被自定义 线程池中的线程执行。

static void Main(string[] args)
{
using (var dr = new Dispatcher())
{
using (var taskQueue = new DispatcherQueue("samples", dr))
{
// Examples will go here...

// Need a blocking call to prevent the application
// exiting.

Console.ReadLine();
}
}
}