共用方式為


非同步代理程式程式庫

非同步代理程式程式庫 (或簡稱為「代理程式程式庫」(Agents Library)) 所提供的程式設計模型,可讓您具有並行功能的應用程式開發更為健全。 代理程式程式庫是 C++ 範本程式庫,可提升以動作項目為基礎的程式設計模型,以及針對粗略資料流程和管線工作所傳遞的同處理序訊息。 代理程式程式庫建置於並行執行階段的排程及資源管理元件上。

程式設計模型

代理程式程式庫可讓您透過以資料流程 (而非控制流程) 為基礎的非同步通訊模型連接隔離的元件,以共用狀態以外的形式作業。 「資料流程」(Dataflow) 是指會在所有必要資料皆可用的情況下執行計算的程式設計模型;「控制流程」(Control Flow) 則是指以預先決定的順序執行計算的程式設計模型。

資料流程程式設計模型與「訊息傳遞」(Message Passing) 的概念有關;在此模型中,程式的獨立元件可藉由訊息傳送相互通訊。

代理程式程式庫由三項元件所組成:「非同步代理程式」(Asynchronous Agent)、「非同步訊息區」(Asynchronous Message Block) 和「訊息傳遞函式」(Message-passing Function)。 代理程式可維護狀態,並使用訊息區和訊息傳遞函式相互通訊以及與外部元件通訊。 訊息傳遞函式可讓代理程式傳送和接收進出於外部元件的訊息。 非同步訊息區可保存郵件,並可讓代理程式以同步方式進行通訊。

下圖說明兩個代理程式如何使用訊息區和訊息傳遞函式進行通訊。 在此圖例中,agent1 使用 Concurrency::send 函式和 Concurrency::unbounded_buffer 物件將訊息傳送至 agent2agent2 使用 Concurrency::receive 函式讀取訊息。 agent2 使用相同的方法將訊息傳送至 agent1。 虛線箭號表示代理程式之間的資料流程。 實心箭號會將代理程式連接至它們所寫入或讀取的訊息區。

代理程式程式庫的元件

本主題稍後將顯示實作此圖例的程式碼範例。

與其他並行和同步處理機制 (例如事件) 相較,代理程式的程式設計模型有幾項優點。 其中一個優點是,使用訊息傳遞藉以傳輸物件之間的狀態變更,可讓您隔離共用資源的存取,進而提升延展性。 訊息傳遞的好處在於,它會將同步處理繫結到資料,而不是繫結到外部同步處理物件。 這簡化了元件之間的資料傳輸,並且可以消除您應用程式中的程式設計錯誤。

使用代理程式程式庫的時機

當您有多個必須以非同步方式相互通訊的作業時,請使用代理程式程式庫。 訊息區和訊息傳遞函式可讓您直接撰寫平行應用程式,而無須使用同步處理機制 (例如鎖定)。 這可以讓您專注於應用程式邏輯上。

代理程式的程式設計模型通常用來建立「資料管線」(Data Pipeline) 或「網路」(Network)。 資料管線是一系列的元件,各個元件分別執行一項特定工作,進而完成較大的目標。 資料流程管線中的每項元件接收到來自其他元件的訊息時,就會開始執行工作。 該工作的結果會傳遞至管線或網路中的其他元件。 這些元件可以使用其他程式庫中更為精細的並行功能,例如 平行模式程式庫 (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'.

下列主題將說明此範例中所使用的功能。

相關主題