Gewusst wie: Schreiben einer parallel_for_each-Schleife

In diesem Beispiel wird gezeigt, wie der Concurrency::parallel_for_each-Algorithmus verwendet wird, um die Anzahl von Primzahlen in einem Concurrency::array-Objekt parallel zu berechnen.

Beispiel

Im folgenden Beispiel wird die Anzahl von Primzahlen in einem Array zweimal berechnet. Im Beispiel wird zunächst die Anzahl mit dem std::for_each-Algorithmus seriell berechnet. Anschließend wird die gleiche Aufgabe mit dem parallel_for_each-Algorithmus parallel ausgeführt. Das Beispiel gibt außerdem die Zeit, die zum Ausführen beider Berechnungen benötigt wird, in der Konsole aus.

// parallel-count-primes.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <iostream>
#include <algorithm>
#include <array>

using namespace Concurrency;
using namespace std;

// Calls the provided work function and returns the number of milliseconds 
// that it takes to call that function.
template <class Function>
__int64 time_call(Function&& f)
{
   __int64 begin = GetTickCount();
   f();
   return GetTickCount() - begin;
}

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

int wmain()
{
   // Create an array object that contains 200000 integers.
   array<int, 200000> a;

   // Initialize the array such that a[i] == i.
   int n = 0;
   generate(a.begin(), a.end(), [&] {
      return n++;
   });

   LONG prime_count;
   __int64 elapsed;

   // Use the for_each algorithm to count the number of prime numbers
   // in the array serially.
   prime_count = 0L;
   elapsed = time_call([&] {
      for_each (a.begin(), a.end(), [&](int n ) { 
         if (is_prime(n))
            ++prime_count;
      });
   });
   wcout << L"serial version: " << endl
         << L"found " << prime_count << L" prime numbers" << endl
         << L"took " << elapsed << L" ms" << endl << endl;

   // Use the parallel_for_each algorithm to count the number of prime numbers
   // in the array in parallel.
   prime_count = 0L;
   elapsed = time_call([&] {
      parallel_for_each (a.begin(), a.end(), [&](int n ) { 
         if (is_prime(n))
            InterlockedIncrement(&prime_count);
      });
   });
   wcout << L"parallel version: " << endl
         << L"found " << prime_count << L" prime numbers" << endl
         << L"took " << elapsed << L" ms" << endl << endl;
}

Die folgende Beispielausgabe entspricht einem Ergebnis auf einem Computer mit vier Prozessoren.

serial version:
found 17984 prime numbers
took 6115 ms

parallel version:
found 17984 prime numbers
took 1653 ms

Kompilieren des Codes

Kopieren Sie den Code zum Kompilieren in ein Visual Studio-Projekt, oder fügen Sie ihn in eine Datei mit dem Namen parallel-count-primes.cpp ein, und führen Sie dann den folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster aus.

cl.exe /EHsc parallel-count-primes.cpp

Robuste Programmierung

Der Lambda-Ausdruck, der im Beispiel an den parallel_for_each-Algorithmus übergeben wird, aktiviert mithilfe der InterlockedIncrement-Funktion parallele Iterationen der Schleife, um den Zähler gleichzeitig zu inkrementieren. Wenn Sie Funktionen wie z. B. InterlockedIncrement verwenden, um Zugriff auf freigegebene Ressourcen zu synchronisieren, kann es zu Leistungsengpässen im Code kommen. Sie können einen Synchronisierungsmechanismus ohne Sperren verwenden, z. B. die Concurrency::combinable-Klasse, um den gleichzeitigen Zugriff auf freigegebene Ressourcen zu vermeiden. Ein Beispiel, in dem die combinable-Klasse auf diese Weise verwendet wird, finden Sie unter Gewusst wie: Verbessern der Leistung mithilfe von combinable.

Siehe auch

Referenz

parallel_for_each-Funktion

Konzepte

Parallele Algorithmen