Compartir a través de


Cómo: Convertir un bucle OpenMP paralelo para usar el runtime de simultaneidad

En este ejemplo se muestra cómo convertir un bucle básico que usa las directivas OpenMP parallel y for para usar el algoritmo Concurrency::parallel_for del runtime de simultaneidad.

Ejemplo

En este ejemplo se usan OpenMP y el runtime de simultaneidad para calcular el contador de números primos en una matriz de valores aleatorios.

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

Este ejemplo produce el siguiente resultado.

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

El algoritmo parallel_for y OpenMP 3.0 permiten que el tipo de índice sea un tipo entero con signo o un tipo entero sin signo. El algoritmo parallel_for también se asegura de que el intervalo especificado no desborde un tipo con signo. Las versiones 2.0 y 2.5 de OpenMP solo permiten los tipos enteros de índice con signo. Además, OpenMP no valida el intervalo de índices.

La versión de este ejemplo que usa el runtime de simultaneidad también emplea un objeto Concurrency::combinable en lugar de la directiva atomic para aumentar el valor del contador sin necesidad de sincronización.

Para obtener más información sobre parallel_for y otros algoritmos paralelos, vea Algoritmos paralelos. Para obtener más información sobre la clase combinable, vea Contenedores y objetos paralelos.

En este ejemplo se modifica el anterior para actuar sobre un objeto std::array en lugar de actuar sobre una matriz nativa. Dado que las versiones 2.0 y 2.5 de OpenMP solo permiten los tipos enteros de índice con signo en una construcción parallel for, no se pueden usar iteradores para obtener acceso a los elementos de un contenedor de la biblioteca de plantillas estándar (STL) en paralelo. La biblioteca de modelos de procesamiento paralelo (PPL) proporciona el algoritmo Concurrency::parallel_for_each, que realiza las tareas, en paralelo, en un contenedor iterativo como los que proporciona STL. Usa la misma lógica de creación de particiones que el algoritmo parallel_for. El algoritmo parallel_for_each se parece al algoritmo std::for_each, con la salvedad de que el algoritmo parallel_for_each ejecuta las tareas de forma simultánea.

// 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(a.begin(), a.end(), [&counts](int n) 
   {
      if (is_prime(n)) {
         counts.local()++;
      }
   });

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

Compilar el código

Copie el código de ejemplo y péguelo en un proyecto de Visual Studio o péguelo en un archivo denominado concrt-omp-count-primes.cpp y, a continuación, ejecute el siguiente comando en una ventana del símbolo del sistema de Visual Studio 2010.

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

Vea también

Conceptos

Algoritmos paralelos

Contenedores y objetos paralelos

Otros recursos

Migrar de OpenMP al Runtime de simultaneidad