Gewusst wie: Konvertieren einer parallel-for-Schleife in OpenMP zur Verwendung der Concurrency Runtime
Dieses Beispiel veranschaulicht, wie eine einfache Schleife, in der die parallel-Direktive und die for-Direktive von OpenMP verwendet werden, für die Verwendung des concurrency::parallel_for-Algorithmus der Concurrency Runtime konvertiert wird.
Beispiel
In diesem Beispiel wird die Anzahl der Primzahlen in einem Array von Zufallswerten sowohl mit OpenMP als auch mit der Concurrency Runtime berechnet.
// 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;
}
Folgende Ergebnisse werden zurückgegeben:
Der parallel_for-Algorithmus und OpenMP 3.0 lassen als Indextyp einen ganzzahligen Typ mit Vorzeichen und einen ganzzahligen Typ ohne Vorzeichen zu. Der parallel_for-Algorithmus stellt außerdem sicher, dass der angegebene Bereich bei einem Typ mit Vorzeichen keinen Überlauf verursacht. Version 2.0 und 2.5 von OpenMP lassen nur ganzzahlige Indextypen mit Vorzeichen zu. In OpenMP wird außerdem der Indexbereich nicht überprüft.
In der Version dieses Beispiels mit der Concurrency Runtime wird außerdem statt der atomic-Direktive ein concurrency::combinable-Objekt verwendet, um den Zählerwert zu erhöhen, ohne dass Synchronisierung erforderlich ist.
Weitere Informationen zu parallel_for und anderen parallelen Algorithmen finden Sie unter Parallele Algorithmen. Weitere Informationen über die combinable-Klasse finden Sie unter Parallele Container und Objekte.
Dieses Beispiel unterscheidet sich vom vorherigen Beispiel darin, dass statt eines systemeigenen Arrays ein std::array-Objekt verwendet wird. Da in OpenMP, Version 2.0 und 2.5, ganzzahlige Indextypen mit Vorzeichen nur in einem parallel for-Konstrukt zulässig sind, können Sie für den parallelen Zugriff auf die Elemente eines STL (Standard Template Library)-Containers keine Iteratoren verwenden. Die Parallel Patterns Library (PPL) stellt den concurrency::parallel_for_each-Algorithmus bereit, der Aufgaben für einen iterativen Container, z. B. einen STL-Container, parallel ausführt. Er verwendet die gleiche Partitionierungslogik wie der parallel_for-Algorithmus. Der parallel_for_each-Algorithmus ähnelt dem std::for_each-Algorithmus der STL, mit dem Unterschied, dass der parallel_for_each-Algorithmus die Aufgaben gleichzeitig ausführt.
// 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;
}
Kompilieren des Codes
Kopieren Sie den Beispielcode, und fügen Sie ihn in ein Visual Studio-Projekt ein. Alternativ dazu können Sie ihn auch in eine Datei mit dem Namen concrt-omp-count-primes.cpp einfügen und dann folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster ausführen.
cl.exe /EHsc /openmp concrt-omp-count-primes.cpp