共用方式為


非同步代理程式程式庫

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

程式設計模型

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

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

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

下圖說明兩個代理程式如何使用訊息區和訊息傳遞函式進行通訊。在此圖例中, agent1傳送訊息給agent2藉由使用 concurrency::send 函式和 concurrency::unbounded_buffer 物件。agent2使用 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'.

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

相關主題