비동기 에이전트 라이브러리
비동기 에이전트 라이브러리(에이전트 라이브러리라고도 함)에서는 동시성 사용 응용 프로그램 개발의 안정성을 향상시킬 수 있는 프로그래밍 모델을 제공합니다. 에이전트 라이브러리는 정교하지 않은 데이터 흐름 및 파이프라인 작업을 위해 행위자 기반 프로그래밍 모델과 in-process 메시지 전달을 촉진하는 C++ 템플릿 라이브러리입니다. 에이전트 라이브러리는 동시성 런타임의 일정 예약 및 리소스 관리 구성 요소를 바탕으로 합니다.
프로그래밍 모델
에이전트 라이브러리는 격리된 구성 요소를 제어 흐름 대신 데이터 흐름을 기반으로 하는 비동기 통신 모델을 통해 연결할 수 있도록 하여 공유 상태에 대한 대안을 제공합니다. 데이터 흐름은 필요한 모든 데이터를 사용할 수 있을 때 계산이 실행되는 프로그래밍 모델을 나타내고 제어 흐름은 미리 결정된 순서로 계산이 실행되는 프로그래밍 모델을 나타냅니다.
데이터 흐름 프로그래밍 모델은 프로그램의 개별 구성 요소가 메시지를 보내 다른 구성 요소와 통신하는 메시지 전달 개념과 관련되어 있습니다.
에이전트 라이브러리는 비동기 에이전트, 비동기 메시지 블록 및 메시지 전달 함수라는 세 가지 구성 요소로 구성됩니다. 에이전트는 상태를 유지 관리하고 메시지 블록 및 메시지 전달 함수를 사용하여 내부의 다른 구성 요소 및 외부 구성 요소와 통신합니다. 메시지 전달 함수는 에이전트가 외부 구성 요소와 메시지를 주고 받을 수 있도록 합니다. 비동기 메시지 블록은 메시지를 보관하고 에이전트가 동기화된 방식으로 통신할 수 있도록 합니다.
다음 그림에서는 두 에이전트가 메시지 블록 및 메시지 전달 함수를 사용하여 통신하는 방법을 보여 줍니다. 이 그림에서 agent1은 Concurrency::send 함수 및 Concurrency::unbounded_buffer 개체를 사용하여 agent2에 메시지를 보냅니다. agent2는 Concurrency::receive 함수를 사용하여 메시지를 읽습니다. agent2는 같은 메서드를 사용하여 agent1에 메시지를 보냅니다. 파선으로 된 화살표는 에이전트 간의 데이터 흐름을 나타내고, 실선으로 된 화살표는 메시지를 쓰거나 읽는 메시지 블록에 에이전트를 연결합니다.
이 그림을 구현하는 코드 예제는 이 항목의 뒷부분에 나옵니다.
에이전트 프로그래밍 모델은 다른 동시성 및 동기화 메커니즘(예: 이벤트)과 비교하여 몇 가지 이점이 있습니다. 그 중 하나는 메시지 전달을 통해 개체 간에 상태 변경을 전송하여 공유 리소스에 대한 액세스를 격리시킬 수 있으므로 확장성을 향상시킬 수 있다는 점입니다. 메시지 전달은 동기화를 외부 동기화 개체 대신 데이터와 연결한다는 이점이 있습니다. 이렇게 하면 구성 요소 사이의 데이터 전송이 간단해지고 응용 프로그램에서 프로그래밍 오류를 없앨 수 있습니다.
에이전트 라이브러리를 사용하는 경우
서로 비동기적으로 통신해야 하는 작업이 여러 개 있는 경우 에이전트 라이브러리를 사용합니다. 메시지 블록 및 메시지 전달 함수를 사용하면 잠금과 같은 동기화 메커니즘이 없어도 병렬 응용 프로그램을 작성할 수 있습니다. 이렇게 하면 응용 프로그램 논리에 초점을 맞출 수 있습니다.
에이전트 프로그래밍 모델은 대개 데이터 파이프라인 또는 네트워크를 만드는 데 사용됩니다. 데이터 파이프라인은 더 큰 목표를 위해 각각 특정 작업을 수행하는 일련의 구성 요소입니다. 데이터 흐름 파이프라인의 모든 구성 요소는 다른 구성 요소로부터 메시지를 받으면 작업을 수행합니다. 해당 작업의 결과는 파이프라인 또는 네트워크의 다른 구성 요소에 전달됩니다. 이러한 구성 요소는 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'.
다음 항목에서는 이 예제에 사용된 기능을 설명합니다.
관련 항목
비동기 에이전트
규모가 큰 컴퓨팅 작업을 해결하기 위한 비동기 에이전트의 역할에 대해 설명합니다.비동기 메시지 블록
에이전트 라이브러리에서 제공하는 다양한 메시지 블록 형식에 대해 설명합니다.메시지 전달 함수
에이전트 라이브러리에서 제공하는 다양한 메시지 전달 루틴에 대해 설명합니다.방법: 다양한 공급자/소비자 패턴 구현
응용 프로그램에서 공급자/소비자 패턴을 구현하는 방법에 대해 설명합니다.방법: call 및 transformer 클래스에 작업 함수 제공
Concurrency::call 및 Concurrency::transformer 클래스에 작업 함수를 제공하는 몇 가지 방법을 보여 줍니다.방법: 데이터 파이프라인에서 transformer 사용
데이터 파이프라인에서 Concurrency::transformer 클래스를 사용하는 방법을 보여 줍니다.방법: 완료된 작업 간 선택
Concurrency::choice 및 Concurrency::join 클래스를 사용하여 검색 알고리즘을 완료할 첫 번째 작업을 선택하는 방법을 보여 줍니다.방법: 정기적으로 메시지 보내기
Concurrency::timer 클래스를 사용하여 정기적으로 메시지를 보내는 방법을 보여 줍니다.방법: 메시지 블록 필터 사용
필터를 사용하여 비동기 메시지 블록에서 메시지를 수락하거나 거부할 수 있도록 설정하는 방법에 대해 설명합니다.PPL(병렬 패턴 라이브러리)
응용 프로그램에서 병렬 알고리즘과 같은 다양한 병렬 패턴을 사용하는 방법에 대해 설명합니다.동시성 런타임
병렬 프로그래밍을 단순화하는 동시성 런타임에 대해 설명하고 관련 항목에 대한 링크를 포함합니다.