Procedura: utilizzare la classe combinable per migliorare le prestazioni
In questo esempio viene illustrato come utilizzare il concurrency::combinable classe per calcolare la somma dei numeri in un std::array oggetto sono i primi.La classe combinable migliora le prestazioni eliminando lo stato condiviso.
Suggerimento |
---|
In alcuni casi, parallelo mappa (concurrency::parallel_transform) e ridurre (la concorrenza:: parallel_reduce) in grado di fornire prestazioni migliori su combinable.Per un esempio che utilizza mapping e ridurre le operazioni per produrre gli stessi risultati di questo esempio, vedere Gli algoritmi paralleli. |
Esempio
Nell'esempio seguente viene utilizzata la funzione std::accumulate per calcolare la somma dei numeri primi di una matrice.In questo esempio a è un oggetto array e la funzione is_prime determina se il relativo valore di input è un numero primo.
prime_sum = accumulate(begin(a), end(a), 0, [&](int acc, int i) {
return acc + (is_prime(i) ? i : 0);
});
Nell'esempio seguente viene illustrata una modalità naïve per parallelizzare l'esempio precedente.Questo esempio viene utilizzata la concurrency::parallel_for_each algoritmo per l'elaborazione della matrice in parallelo e un concurrency::critical_section oggetto per sincronizzare l'accesso per il prime_sum variabile.Questo esempio non è adatto perché ogni thread deve attendere che la risorsa condivisa diventi disponibile.
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();
});
Nell'esempio seguente viene utilizzato un oggetto combinable per migliorare le prestazioni dell'esempio precedente.Questo esempio elimina la necessità di oggetti di sincronizzazione ed è adatto poiché l'oggetto combinable consente a ogni thread di eseguire la relativa attività indipendentemente.
Un oggetto combinable viene utilizzato in genere in due passaggi.Nel primo produrre una serie di calcoli accurati eseguendo il lavoro in parallelo.Nel secondo combinare o ridurre i calcoli in un risultato finale.Questo esempio viene utilizzata la concurrency::combinable::local metodo per ottenere un riferimento per la somma in locale.Viene quindi utilizzata la concurrency::combinable::combine metodo e un std::plus oggetto per combinare i calcoli locali nel risultato finale.
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>());
Nell'esempio completo seguente viene calcolata la somma dei numeri primi sia in serie che in parallelo.L'esempio visualizza nella console il tempo necessario per eseguire entrambi i calcoli.
// 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;
}
L'output di esempio seguente è relativo a un computer con quattro processori.
1709600813
serial time: 6178 ms
1709600813
parallel time: 1638 ms
Compilazione del codice
Per compilare il codice, copiarlo e incollarlo in un progetto di Visual Studio o incollarlo in un file denominato parallelo somma di primes.cpp e quindi eseguire il comando riportato di seguito in una finestra del prompt dei comandi di Visual Studio.
cl.exe /EHsc parallel-sum-of-primes.cpp
Programmazione efficiente
Per un esempio che utilizza mapping e ridurre le operazioni per produrre gli stessi risultati, vedere Gli algoritmi paralleli.