PPL(병렬 패턴 라이브러리)
PPL(병렬 패턴 라이브러리)은 동시 응용 프로그램 개발을 위해 사용 편리성 및 확장성을 향상시키는 명령형 프로그래밍 모델을 제공합니다.PPL은 동시성 런타임의 일정 예약 및 리소스 관리 구성 요소를 바탕으로 합니다.이는 데이터에 대해 형식이 안전한 제네릭 알고리즘 및 컨테이너를 동시에 제공하여 응용 프로그램 코드와 내부 스레딩 메커니즘 간의 추상화 수준을 높입니다.또한 PPL을 사용하면 공유 상태에 대한 대안을 제공하여 크기를 조정하는 응용 프로그램을 개발할 수 있습니다.
PPL은 다음과 같은 기능을 제공합니다.
작업 병렬 처리: 여러 작업 항목(작업)을 동시에 실행하는 메커니즘입니다.
병렬 알고리즘: 데이터 컬렉션에 대해 동시에 수행되는 제네릭 알고리즘입니다.
병렬 컨테이너 및 개체: 요소에 대해 안전한 동시 액세스를 제공하는 제네릭 컨테이너 형식입니다.
예제
PPL은 STL(표준 템플릿 라이브러리)과 유사한 프로그래밍 모델을 제공합니다.다음 예제에서는 PPL의 여러 기능을 보여 주고몇 가지 피보나치(Fibonacci) 수를 연속적으로 또는 병렬로 계산합니다.두 계산은 모두 std::array 개체에 대해 작용합니다.또한 두 계산을 모두 수행하는 데 필요한 시간을 콘솔에 출력합니다.
연속 버전은 STL std::for_each 알고리즘을 사용하여 배열을 트래버스하고 결과를 std::vector 개체에 저장합니다.병렬 버전 동일한 작업을 수행 하지만 PPL을 사용 하 여 concurrency::parallel_for_each 알고리즘에 결과 저장 하 고는 concurrency::concurrent_vector 개체입니다.concurrent_vector 클래스를 사용하면 컨테이너에 대한 쓰기 권한을 동기화하지 않고도 루프 반복에서 동시에 요소를 추가할 수 있습니다.
parallel_for_each는 동시에 동작하므로 이 예제의 병렬 버전은 연속 버전과 같은 결과가 나타나도록 concurrent_vector 개체를 정렬해야 합니다.
이 예제에서는 단순한 메서드를 사용하여 피보나치(Fibonacci) 수를 계산하지만 이 메서드는 동시성 런타임에서 긴 계산의 성능을 향상시킬 수 있는 방법을 보여 줍니다.
// parallel-fibonacci.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <concurrent_vector.h>
#include <array>
#include <vector>
#include <tuple>
#include <algorithm>
#include <iostream>
using namespace concurrency;
using namespace std;
// Calls the provided work function and returns the number of milliseconds
// that it takes to call that function.
template <class Function>
__int64 time_call(Function&& f)
{
__int64 begin = GetTickCount();
f();
return GetTickCount() - begin;
}
// Computes the nth Fibonacci number.
int fibonacci(int n)
{
if(n < 2)
return n;
return fibonacci(n-1) + fibonacci(n-2);
}
int wmain()
{
__int64 elapsed;
// An array of Fibonacci numbers to compute.
array<int, 4> a = { 24, 26, 41, 42 };
// The results of the serial computation.
vector<tuple<int,int>> results1;
// The results of the parallel computation.
concurrent_vector<tuple<int,int>> results2;
// Use the for_each algorithm to compute the results serially.
elapsed = time_call([&]
{
for_each (begin(a), end(a), [&](int n) {
results1.push_back(make_tuple(n, fibonacci(n)));
});
});
wcout << L"serial time: " << elapsed << L" ms" << endl;
// Use the parallel_for_each algorithm to perform the same task.
elapsed = time_call([&]
{
parallel_for_each (begin(a), end(a), [&](int n) {
results2.push_back(make_tuple(n, fibonacci(n)));
});
// Because parallel_for_each acts concurrently, the results do not
// have a pre-determined order. Sort the concurrent_vector object
// so that the results match the serial version.
sort(begin(results2), end(results2));
});
wcout << L"parallel time: " << elapsed << L" ms" << endl << endl;
// Print the results.
for_each (begin(results2), end(results2), [](tuple<int,int>& pair) {
wcout << L"fib(" << get<0>(pair) << L"): " << get<1>(pair) << endl;
});
}
다음 샘플은 프로세서가 4개인 컴퓨터에 대한 출력입니다.
serial time: 9250 ms
parallel time: 5726 ms
fib(24): 46368
fib(26): 121393
fib(41): 165580141
fib(42): 267914296
루프의 각 반복에서는 작업을 끝내는 시간이 서로 다릅니다.parallel_for_each의 성능은 마지막에 끝내는 작업에 의해 제한됩니다.그러므로 이 예제에서 연속 버전과 병렬 버전 간의 선형 성능 향상을 기대하면 안 됩니다.
관련 항목
제목 |
설명 |
---|---|
PPL의 작업 및 작업 그룹의 역할에 대해 설명합니다. |
|
parallel_for 및 parallel_for_each와 같은 병렬 알고리즘을 사용하는 방법에 대해 설명합니다. |
|
PPL에서 제공하는 다양한 병렬 컨테이너 및 개체에 대해 설명합니다. |
|
병렬 알고리즘에서 수행 중인 작업을 취소하는 방법에 대해 설명합니다. |
|
병렬 프로그래밍을 단순화하는 동시성 런타임에 대해 설명하고 관련 항목에 대한 링크를 포함합니다. |