异步代理库(或简称为“代理库”)提供了一个编程模型,通过它可以增加启用并发的应用程序开发的可靠性。 代理库是一个 C++ 模板库,它可以提升基于参与者的编程模型和进程内消息传递,以执行细化数据流任务和流水线操作任务。 代理库基于并发运行时的计划和资源管理组件生成。
代理库可提供共享状态的备选方案,方法是让您通过基于数据流(而不是控制流)的异步通信模型来连接独立的组件。 “数据流”指的是在所有必需的数据都可用时进行计算的编程模型;“控件流”指的是按预先确定的顺序进行计算的编程模型。
数据流编程模型与“消息传递”概念相关,在消息传递中,某个程序的独立组件通过发送消息与另一个程序进行通信。
代理库由三个组件组成:“异步代理”、“异步消息块”和“消息传递函数”。 代理维护状态,并使用消息块和消息传递函数与另一个组件和外部组件进行通信。 通过消息传递函数,代理可以将消息发送到外部组件和从外部组件接收消息。 异步消息块存放消息,并使通信能够以同步的方式进行通信。
下图显示了两个代理如何使用消息块和消息传递函数进行通信。 在此图中, agent1会发送一条消息, agent2使用 concurrency::send 函数和concurrency::unbounded_buffer 对象。 agent2使用 concurrency::receive 函数即可阅读邮件。 agent2 使用相同的方法向 agent1 发送消息。 虚线箭头表示代理之间的数据流。 实线箭头将代理连接到它们在其中写入或读取的消息块。
![代理库的组件 代理库的组件](http://i.msdn.microsoft.com/dynimg/IC387474.png)
本主题后面将显示实现此图的代码示例。
代理编程模型具有其他并发和同步机制(如事件)所没有的一些优点。 一个优点是:通过使用消息传递在对象之间传输状态更改,您可以隔离对共享资源的访问,从而提高可伸缩性。 消息传递的优点是它将同步绑定到数据,而不是绑定到外部的同步对象。 这简化了组件之间的数据传输,并可以消除应用程序中的编程错误。
当您有多个必须彼此异步通信的操作时,使用代理库。 使用消息块和消息传递函数,无需同步机制(如锁)即可编写并行应用程序。 这使您可以将精力集中在应用程序逻辑上。
代理编程模型通常用于创建数据管道或网络。 数据管道是一系列组件,每个组件执行一个参与更大目标的特定任务。 数据流管道中的每个组件从另一个组件接收消息时执行工作。 该工作的结果传递到管道或网络中的其他组件。 这些组件可以使用其他库(如并行模式库 (PPL))中的更细化的并发功能。
下面的示例实现本主题前面所示的图示。
// basic-agents.cpp // compile with: /EHsc #include <agents.h> #include <string> #include <iostream> #include <sstream> using namespace concurrency; using namespace std; // This agent writes a string to its target and reads an integer // from its source. class agent1 : public agent { public: explicit agent1(ISource<int>& source, ITarget<wstring>& target) : _source(source) , _target(target) { } protected: void run() { // Send the request. wstringstream ss; ss << L"agent1: sending request..." << endl; wcout << ss.str(); send(_target, wstring(L"request")); // Read the response. int response = receive(_source); ss = wstringstream(); ss << L"agent1: received '" << response << L"'." << endl; wcout << ss.str(); // Move the agent to the finished state. done(); } private: ISource<int>& _source; ITarget<wstring>& _target; }; // This agent reads a string to its source and then writes an integer // to its target. class agent2 : public agent { public: explicit agent2(ISource<wstring>& source, ITarget<int>& target) : _source(source) , _target(target) { } protected: void run() { // Read the request. wstring request = receive(_source); wstringstream ss; ss << L"agent2: received '" << request << L"'." << endl; wcout << ss.str(); // Send the response. ss = wstringstream(); ss << L"agent2: sending response..." << endl; wcout << ss.str(); send(_target, 42); // Move the agent to the finished state. done(); } private: ISource<wstring>& _source; ITarget<int>& _target; }; int wmain() { // Step 1: Create two message buffers to serve as communication channels // between the agents. // The first agent writes messages to this buffer; the second // agents reads messages from this buffer. unbounded_buffer<wstring> buffer1; // The first agent reads messages from this buffer; the second // agents writes messages to this buffer. overwrite_buffer<int> buffer2; // Step 2: Create the agents. agent1 first_agent(buffer2, buffer1); agent2 second_agent(buffer1, buffer2); // Step 3: Start the agents. The runtime calls the run method on // each agent. first_agent.start(); second_agent.start(); // Step 4: Wait for both agents to finish. agent::wait(&first_agent); agent::wait(&second_agent); }
该示例产生下面的输出:
agent1: sending request... agent2: received 'request'. agent2: sending response... agent1: received '42'.
下面的主题描述该示例中使用的功能。