Freigeben über


Gewusst wie: Konvertieren einer parallel-for-Schleife in OpenMP zur Verwendung der Concurrency Runtime

In diesem Beispiel wird veranschaulicht, wie eine einfache Schleife konvertiert wird, die die OpenMP-Parallele verwendet, und für Direktiven die Parallelitäts-Runtime-Parallelität::p arallel_for-Algorithmus verwenden.

Beispiel : Primzahl

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:

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

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.

Die Version dieses Beispiels, die die Concurrency Runtime verwendet, verwendet auch ein paralleles::kombinationsfähiges Objekt anstelle der Atomdirektive , um den Gegenwert zu erhöhen, ohne dass eine Synchronisierung erforderlich ist.

Weitere Informationen zu parallel_for und anderen parallelen Algorithmen finden Sie unter Parallel-Algorithmen. Weitere Informationen zur combinable Klasse finden Sie unter Parallel Containers and Objects.

Beispiel : verwenden von std::array

In diesem Beispiel wird das vorherige Objekt geändert, um auf ein std::array-Objekt anstelle eines systemeigenen Arrays zu reagieren. Da die OpenMP-Versionen 2.0 und 2.5 signierte integrale Indextypen nur in einem parallel_for Konstrukt zulassen, können Sie iteratoren nicht verwenden, um parallel auf die Elemente eines C++-Standardbibliothekscontainers zuzugreifen. Die Parallel Patterns Library (PPL) stellt die parallele Parallelität::p arallel_for_each Algorithmus bereit, die Aufgaben parallel für einen iterativen Container ausführt, z. B. die von der C++-Standardbibliothek bereitgestellten. Er verwendet die gleiche Partitionierungslogik wie der parallel_for-Algorithmus. Der parallel_for_each Algorithmus ähnelt dem C++-Standardbibliotheksalgorithmus std::for_each , mit der Ausnahme, 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, fügen Sie ihn in ein Visual Studio-Projekt ein, oder fügen Sie ihn in eine Datei ein, die benannt concrt-omp-count-primes.cpp ist, und führen Sie dann den folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster aus.

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

Siehe auch

Migrieren von OpenMP zur Concurrency Runtime
Parallele Algorithmen
Parallele Container und Objekte