Condividi tramite


Procedura: Convertire un ciclo OpenMP parallel for per l'utilizzo del runtime di concorrenza

In questo esempio viene illustrato come convertire un ciclo di base che usa il parallelismo OpenMP e per le direttive per usare l'algoritmo Concurrency Runtime concurrency::p arallel_for.

Esempio : conteggio dei numeri primi

Questo esempio usa sia OpenMP che Il runtime di concorrenza per calcolare il conteggio dei numeri primi in una matrice di valori casuali.

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

Questo esempio produce il seguente output:

Using OpenMP...
found 107254 prime numbers.
Using the Concurrency Runtime...
found 107254 prime numbers.

L'algoritmo parallel_for e OpenMP 3.0 consentono al tipo di indice di essere un tipo integrale con segno o un tipo integrale senza segno. L'algoritmo parallel_for assicura inoltre che l'intervallo specificato non sovraflow un tipo con segno. Le versioni OpenMP 2.0 e 2.5 consentono solo tipi di indice integrale con segno. OpenMP non convalida anche l'intervallo di indici.

La versione di questo esempio che usa il runtime di concorrenza usa anche un oggetto concurrency::combinable al posto della direttiva atomica per incrementare il valore del contatore senza richiedere la sincronizzazione.

Per altre informazioni su parallel_for e altri algoritmi paralleli, vedere Algoritmi paralleli. Per altre informazioni sulla combinable classe , vedere Contenitori e oggetti paralleli.

Esempio: usare std::array

In questo esempio viene modificato quello precedente per agire su un oggetto std::array anziché su una matrice nativa. Poiché le versioni OpenMP 2.0 e 2.5 consentono i tipi di indice integrale con segno solo in un parallel_for costrutto, non è possibile usare iteratori per accedere agli elementi di un contenitore della libreria standard C++ in parallelo. La libreria PPL (Parallel Patterns Library) fornisce l'algoritmo concurrency::p arallel_for_each , che esegue attività in parallelo su un contenitore iterativo, ad esempio quelli forniti dalla libreria standard C++. Usa la stessa logica di partizionamento usata dall'algoritmo parallel_for . L'algoritmo parallel_for_each è simile all'algoritmo std::for_each della libreria standard C++, ad eccezione del fatto che l'algoritmo parallel_for_each esegue le attività contemporaneamente.

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

Compilazione del codice

Copiare il codice di esempio e incollarlo in un progetto di Visual Studio oppure incollarlo in un file denominato concrt-omp-count-primes.cpp e quindi eseguire il comando seguente in una finestra del prompt dei comandi di Visual Studio.

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

Vedi anche

Migrazione da OpenMP al runtime di concorrenza
Algoritmi paralleli
Contenitori e oggetti paralleli