방법: combinable을 사용하여 성능 개선
이 예제에서는 동시성::결합 가능한 클래스를 사용하여 소수인 std::array 개체의 숫자 합계를 계산하는 방법을 보여 줍니다. 클래스는 combinable
공유 상태를 제거하여 성능을 향상시킵니다.
팁
경우에 따라 병렬 맵(concurrency::p arel_transform) 및 축소(동시성:: parallel_reduce)는 성능 향상을 combinable
제공할 수 있습니다. 맵 및 축소 작업을 사용하여 이 예제와 동일한 결과를 생성하는 예제는 병렬 알고리즘을 참조 하세요.
예제 - 누적
다음 예제에서는 std::accumulate 함수를 사용하여 소수 배열에 있는 요소의 합계를 계산합니다. 이 예제 a
에서는 개체이며 array
함수는 is_prime
입력 값이 소수인지 여부를 결정합니다.
prime_sum = accumulate(begin(a), end(a), 0, [&](int acc, int i) {
return acc + (is_prime(i) ? i : 0);
});
예제 - parallel_for_each
다음 예제에서는 이전 예제를 병렬화하는 순진한 방법을 보여줍니다. 이 예제에서는 concurrency::p arallel_for_each 알고리즘을 사용하여 배열을 병렬로 처리하고 동시성::critical_section 개체를 사용하여 변수에 prime_sum
대한 액세스를 동기화합니다. 이 예제는 각 스레드가 공유 리소스를 사용할 수 있게 될 때까지 기다려야 하기 때문에 크기를 조정하지 않습니다.
critical_section cs;
prime_sum = 0;
parallel_for_each(begin(a), end(a), [&](int i) {
cs.lock();
prime_sum += (is_prime(i) ? i : 0);
cs.unlock();
});
예제 - 결합 가능
다음 예제에서는 개체를 combinable
사용하여 이전 예제의 성능을 향상시킵니다. 이 예제에서는 동기화 개체가 필요하지 않습니다. 개체를 사용하면 각 스레드가 combinable
독립적으로 작업을 수행할 수 있기 때문에 크기가 조정됩니다.
combinable
개체는 일반적으로 두 단계로 사용됩니다. 먼저 병렬로 작업을 수행하여 일련의 세분화된 계산을 생성합니다. 다음으로 계산을 최종 결과로 결합(또는 축소)합니다. 이 예제에서는 동시성::combinable::local 메서드를 사용하여 로컬 합계에 대한 참조를 가져옵니다. 그런 다음 동시성::combinable::combine 메서드와 std::p lus 개체를 사용하여 로컬 계산을 최종 결과로 결합합니다.
combinable<int> sum;
parallel_for_each(begin(a), end(a), [&](int i) {
sum.local() += (is_prime(i) ? i : 0);
});
prime_sum = sum.combine(plus<int>());
예제 - 직렬 및 병렬
다음 전체 예제에서는 소수의 합계를 직렬 및 병렬로 계산합니다. 이 예제에서는 두 계산을 모두 수행하는 데 필요한 시간을 콘솔에 출력합니다.
// parallel-sum-of-primes.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <array>
#include <numeric>
#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;
}
// Determines whether the input value is prime.
bool is_prime(int n)
{
if (n < 2)
return false;
for (int i = 2; i < n; ++i)
{
if ((n % i) == 0)
return false;
}
return true;
}
int wmain()
{
// Create an array object that contains 200000 integers.
array<int, 200000> a;
// Initialize the array such that a[i] == i.
iota(begin(a), end(a), 0);
int prime_sum;
__int64 elapsed;
// Compute the sum of the numbers in the array that are prime.
elapsed = time_call([&] {
prime_sum = accumulate(begin(a), end(a), 0, [&](int acc, int i) {
return acc + (is_prime(i) ? i : 0);
});
});
wcout << prime_sum << endl;
wcout << L"serial time: " << elapsed << L" ms" << endl << endl;
// Now perform the same task in parallel.
elapsed = time_call([&] {
combinable<int> sum;
parallel_for_each(begin(a), end(a), [&](int i) {
sum.local() += (is_prime(i) ? i : 0);
});
prime_sum = sum.combine(plus<int>());
});
wcout << prime_sum << endl;
wcout << L"parallel time: " << elapsed << L" ms" << endl << endl;
}
프로세서가 4개인 컴퓨터의 샘플 출력은 다음과 같습니다.
1709600813
serial time: 6178 ms
1709600813
parallel time: 1638 ms
코드 컴파일
코드를 컴파일하려면 코드를 복사한 다음 Visual Studio 프로젝트에 붙여넣거나 이름이 지정된 parallel-sum-of-primes.cpp
파일에 붙여넣은 다음 Visual Studio 명령 프롬프트 창에서 다음 명령을 실행합니다.
cl.exe /EHsc parallel-sum-of-primes.cpp
강력한 프로그래밍
맵 및 축소 작업을 사용하여 동일한 결과를 생성하는 예제는 병렬 알고리즘을 참조 하세요.