Gewusst wie: Verbessern der Leistung mithilfe von combinable

In diesem Beispiel wird veranschaulicht die concurrency::combinable Klasse zum Berechnen der Summe der Zahlen in einer std::array -Objekt, das Primzahlen sind.Die combinable-Klasse steigert die Leistung, indem sie Freigabezustand ausschließt.

TippTipp

In einigen Fällen parallel-Karte (concurrency::parallel_transform) und reduzieren (Parallelität:: Parallel_reduce) bieten Leistungsverbesserungen in combinable.Ein Beispiel, zuordnen und verringern die produzieren dieselben Ergebnisse wie in diesem Beispiel wird, finden Sie unter Paralleler Algorithmen.

Beispiel

Im folgenden Beispiel wird die std::accumulate-Funktion verwendet, um die Summe der Elemente in einem Array zu berechnen, bei denen es sich um Primzahlen handelt.In diesem Beispiel ist a ein array-Objekt, und die is_prime-Funktion bestimmt, ob sein Eingabewert eine Primzahl ist.

prime_sum = accumulate(begin(a), end(a), 0, [&](int acc, int i) {
   return acc + (is_prime(i) ? i : 0);
});

Das folgende Beispiel zeigt einen naiven Weg, das vorherige Beispiel zu parallelisieren.In diesem Beispiel wird die concurrency::parallel_for_each Algorithmus, um das Array parallel verarbeiten und ein concurrency::critical_section Objekt zum Synchronisieren des Zugriffs auf die prime_sum Variable.Dieses Beispiel skaliert nicht, da jeder Thread warten muss, bis die freigegebene Ressource verfügbar wird.

critical_section cs;
prime_sum = 0;
parallel_for_each(begin(a), end(a), [&](int i) {
   cs.lock();
   prime_sum += (is_prime(i) ? i : 0);
   cs.unlock();
});

Im folgenden Beispiel wird ein combinable-Objekt zum Steigern der Leistung des vorherigen Beispiels verwendet.In diesem Beispiel sind keine Synchronisierungsobjekte erforderlich. Es skaliert, da das combinable-Objekt dafür sorgt, dass jeder Thread seine Aufgabe unabhängig ausführt.

Ein combinable-Objekt wird in der Regel in zwei Schritten verwendet.Erzeugen Sie zuerst eine Reihe von differenzierten Berechnungen, indem Sie Arbeiten parallel ausführen.Fassen Sie danach die Berechnungen in einem Endergebnis zusammen (oder reduzieren Sie sie).In diesem Beispiel wird die Concurrency::combinable::local -Methode, um einen Verweis auf die lokalen Summe zu erhalten.Dann wird die Concurrency::combinable::combine Methode und ein std::plus Objekt, das die lokalen Berechnungen in das Endergebnis zu kombinieren.

combinable<int> sum;
parallel_for_each(begin(a), end(a), [&](int i) {
   sum.local() += (is_prime(i) ? i : 0);
});
prime_sum = sum.combine(plus<int>());

Im folgenden vollständigen Beispiel wird die Summe von Primzahlen sowohl seriell als auch parallel berechnet.Das Beispiel gibt die Zeit, die zum Ausführen beider Berechnungen benötigt wird, in der Konsole aus.

// parallel-sum-of-primes.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <array>
#include <numeric>
#include <iostream>

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.
   iota(begin(a), end(a), 0);

   int prime_sum;
   __int64 elapsed;

   // Compute the sum of the numbers in the array that are prime.
   elapsed = time_call([&] {
      prime_sum = accumulate(begin(a), end(a), 0, [&](int acc, int i) {
         return acc + (is_prime(i) ? i : 0);
      });
   });   
   wcout << prime_sum << endl;   
   wcout << L"serial time: " << elapsed << L" ms" << endl << endl;

   // Now perform the same task in parallel.
   elapsed = time_call([&] {
      combinable<int> sum;
      parallel_for_each(begin(a), end(a), [&](int i) {
         sum.local() += (is_prime(i) ? i : 0);
      });
      prime_sum = sum.combine(plus<int>());
   });
   wcout << prime_sum << endl;
   wcout << L"parallel time: " << elapsed << L" ms" << endl << endl;
}

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

1709600813
serial time: 6178 ms

1709600813
parallel time: 1638 ms

Kompilieren des Codes

Um den Code zu kompilieren, kopieren Sie ihn ein und fügen Sie ihn in einem Projekt Visual Studio oder fügen Sie ihn in eine Datei mit dem Namen Parallel Summe der primes.cpp und führen Sie den folgenden Befehl in ein Visual Studio-Eingabeaufforderungsfenster.

cl.exe /EHsc parallel-sum-of-primes.cpp

Robuste Programmierung

Ein Beispiel, zuordnen und verringern die gleichen Ergebnisse erzielen, finden Sie unter Paralleler Algorithmen.

Siehe auch

Referenz

combinable-Klasse

critical_section-Klasse

Konzepte

Parallele Container und Objekte