Partager via


Comment : convertir une boucle OpenMP parallèle pour utiliser le runtime d'accès concurrentiel

Cet exemple explique comment convertir une boucle de base qui utilise les directives parallel et for OpenMP pour utiliser l'algorithme de runtime d'accès concurrentiel concurrency::parallel_for.

Exemple

Cet exemple utilise OpenMP et le runtime d'accès concurrentiel pour calculer le nombre de nombres premiers dans un tableau de valeurs aléatoires.

// concrt-omp-count-primes.cpp 
// compile with: /EHsc /openmp
#include <ppl.h>
#include <random>
#include <array>
#include <iostream>

using namespace concurrency;
using namespace std;

// 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;
}

// Uses OpenMP to compute the count of prime numbers in an array. 
void omp_count_primes(int* a, size_t size)
{
   if (size == 0)
      return;

   size_t count = 0;
   #pragma omp parallel for 
      for (int i = 0; i < static_cast<int>(size); ++i)
      {
         if (is_prime(a[i])) {
            #pragma omp atomic
               ++count;
         }
      }

   wcout << L"found " << count 
         << L" prime numbers." << endl;
}

// Uses the Concurrency Runtime to compute the count of prime numbers in an array. 
void concrt_count_primes(int* a, size_t size)
{
   if (size == 0)
      return;

   combinable<size_t> counts;
   parallel_for<size_t>(0, size, [&](size_t i) 
   {
      if (is_prime(a[i])) {
         counts.local()++;
      }
   });

   wcout << L"found " << counts.combine(plus<size_t>()) 
         << L" prime numbers." << endl;
}

int wmain()
{
   // The length of the array. 
   const size_t size = 1000000;

   // Create an array and initialize it with random values. 
   int* a = new int[size];

   mt19937 gen(42);
   for (size_t i = 0; i < size; ++i) {
      a[i] = gen();
   }

   // Count prime numbers by using OpenMP and the Concurrency Runtime.

   wcout << L"Using OpenMP..." << endl;
   omp_count_primes(a, size);

   wcout << L"Using the Concurrency Runtime..." << endl;
   concrt_count_primes(a, size);

   delete[] a;
}

Cet exemple génère la sortie suivante.

  

L'algorithme parallel_for et OpenMP 3.0 permettent au type d'index d'être de type intégral signé ou de type intégral non signé. L'algorithme parallel_for vérifie également que la plage spécifiée ne dépasse pas un type signé. Les versions OpenMP 2.0 et 2.5 n'autorisent que les types d'index intégraux signés. OpenMP ne valide pas la plage d'index.

La version de cet exemple qui utilise le runtime d'accès concurrentiel utilise également un objet concurrency::combinable au lieu de la directive atomic pour incrémenter la valeur de compteur sans nécessiter de synchronisation.

Pour plus d'informations sur parallel_for et d'autres algorithmes parallèles, consultez Algorithmes parallèles. Pour plus d'informations sur la classe combinable, consultez Conteneurs et objets parallèles.

Cet exemple modifie l'exemple précédent pour agir sur un objet std::array plutôt que sur un tableau natif. Étant donné que les versions OpenMP 2.0 et 2.5 n'autorisent que les types d'index intégraux signés dans un élément parallel for, vous ne pouvez pas utiliser d'itérateurs pour accéder aux éléments d'un conteneur de la bibliothèque de modèles Standard (STL) en parallèle. La bibliothèque de modèles parallèles (PPL) fournit l'algorithme concurrency::parallel_for_each, qui exécute des tâches, en parallèle, sur un conteneur itératif, tels que ceux fournis par la bibliothèque STL. Il utilise la même logique de partitionnement que l'algorithme parallel_for. L'algorithme parallel_for_each ressemble à l'algorithme std::for_each STL, à l'exception près que l'algorithme parallel_for_each exécute les tâches simultanément.

// Uses OpenMP to compute the count of prime numbers in an  
// array object. 
template<size_t Size>
void omp_count_primes(const array<int, Size>& a)
{
   if (a.size() == 0)
      return;

   size_t count = 0;
   int size = static_cast<int>(a.size());
   #pragma omp parallel for 
      for (int i = 0; i < size; ++i)
      {
         if (is_prime(a[i])) {
            #pragma omp atomic
               ++count;
         }
      }

   wcout << L"found " << count 
         << L" prime numbers." << endl;
}

// Uses the Concurrency Runtime to compute the count of prime numbers in an  
// array object. 
template<size_t Size>
void concrt_count_primes(const array<int, Size>& a)
{
   if (a.size() == 0)
      return;

   combinable<size_t> counts;
   parallel_for_each(begin(a), end(a), [&counts](int n) 
   {
      if (is_prime(n)) {
         counts.local()++;
      }
   });

   wcout << L"found " << counts.combine(plus<size_t>()) 
         << L" prime numbers." << endl;
}

Compilation du code

Copiez l'exemple de code et collez-le dans un projet Visual Studio , ou collez-le dans un fichier nommé concrt-omp-count-primes.cpp. Exécutez ensuite la commande suivante dans une fenêtre d'invite de commandes Visual Studio.

cl.exe /EHsc /openmp concrt-omp-count-primes.cpp

Voir aussi

Concepts

Migration d'OpenMP au runtime d'accès concurrentiel

Algorithmes parallèles

Conteneurs et objets parallèles