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 utilizar el algoritmo concurrency::parallel_for del runtime de simultaneidad.
Ejemplo: recuento de números primos
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 más información sobre parallel_for
y otros algoritmos en paralelo, consulta Algoritmos paralelos. Para más información sobre la clase combinable
, consulte Contenedores y objetos paralelos.
Ejemplo: uso de std::array
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 acceder a los elementos de un contenedor de la biblioteca de plantillas estándar (STL) de C++ en paralelo. La biblioteca de patrones 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 la biblioteca de plantillas estándar de C++. 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 de la biblioteca de plantillas estándar, excepto en 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(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;
}
Compilar el código
Copie el código de ejemplo y péguelo en un proyecto de Visual Studio o en un archivo denominado concrt-omp-count-primes.cpp
y, después, ejecute el siguiente comando en una ventana del símbolo del sistema de Visual Studio.
cl.exe /EHsc /openmp concrt-omp-count-primes.cpp
Consulte también
Migración de OpenMP al Runtime de simultaneidad
Algoritmos paralelos
Contenedores y objetos paralelos