Guide pratique pour écrire une parallel_for_each
boucle
Cet exemple montre comment utiliser l’algorithme concurrency::parallel_for_each
pour calculer le nombre de nombres premiers dans un std::array
objet en parallèle.
Exemple
L’exemple suivant calcule le nombre de nombres premiers dans un tableau deux fois. L’exemple utilise d’abord l’algorithme std::for_each
pour calculer le nombre en série. L’exemple utilise ensuite l’algorithme parallel_for_each
pour effectuer la même tâche en parallèle. L'exemple affiche également sur la console le temps requis pour effectuer les deux calculs.
// parallel-count-primes.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <iostream>
#include <algorithm>
#include <array>
using namespace concurrency;
using namespace std;
// Returns the number of milliseconds that it takes to call the passed in function.
template <class Function>
__int64 time_call(Function&& f)
{
__int64 begin = GetTickCount();
f();
return GetTickCount() - begin;
}
// Determines whether the input is a prime.
bool is_prime(int n)
{
if (n < 2)
{
return false;
}
for (int i = 2; i < int(std::sqrt(n)) + 1; ++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.
int n = 0;
generate(begin(a), end(a), [&]
{
return n++;
});
// Use the for_each algorithm to count, serially, the number
// of prime numbers in the array.
LONG prime_count = 0L;
__int64 elapsed = time_call([&]
{
for_each(begin(a), end(a), [&](int n)
{
if (is_prime(n))
{
++prime_count;
}
});
});
wcout << L"serial version: " << endl
<< L"found " << prime_count << L" prime numbers" << endl
<< L"took " << elapsed << L" ms" << endl << endl;
// Use the parallel_for_each algorithm to count, in parallel, the number
// of prime numbers in the array.
prime_count = 0L;
elapsed = time_call([&]
{
parallel_for_each(begin(a), end(a), [&](int n)
{
if (is_prime(n))
{
InterlockedIncrement(&prime_count);
}
});
});
wcout << L"parallel version: " << endl
<< L"found " << prime_count << L" prime numbers" << endl
<< L"took " << elapsed << L" ms" << endl << endl;
}
L’exemple de sortie suivant concerne un ordinateur qui a quatre cœurs.
serial version:
found 17984 prime numbers
took 125 ms
parallel version:
found 17984 prime numbers
took 63 ms
Compilation du code
Pour compiler le code, copiez-le, collez-le dans un projet Visual Studio ou collez-le dans un fichier nommé parallel-count-primes.cpp
, puis exécutez la commande suivante dans une fenêtre d’invite de commandes Visual Studio.
cl.exe /EHsc parallel-count-primes.cpp
Programmation fiable
L’expression lambda que l’exemple transmet à l’algorithme parallel_for_each
utilise la InterlockedIncrement
fonction pour activer les itérations parallèles de la boucle pour incrémenter le compteur simultanément. Si vous utilisez des fonctions telles que InterlockedIncrement
pour synchroniser l’accès aux ressources partagées, vous pouvez présenter des goulots d’étranglement des performances dans votre code. Vous pouvez utiliser un mécanisme de synchronisation sans verrou, par exemple, la concurrency::combinable
classe, pour éliminer l’accès simultané aux ressources partagées. Pour obtenir un exemple qui utilise la combinable
classe de cette façon, consultez Guide pratique pour améliorer les performances.