Windows Dev Center

Dieser Artikel wurde manuell übersetzt. Bewegen Sie den Mauszeiger über die Sätze im Artikel, um den Originaltext anzuzeigen. Weitere Informationen
Übersetzung
Original
Informationen
Das angeforderte Thema wird unten angezeigt. Es ist jedoch nicht in dieser Bibliothek vorhanden.

Gewusst wie: Verbessern der Leistung mithilfe von combinable

In diesem Beispiel wird gezeigt, wie die concurrency::combinable-Klasse verwendet wird, um die Summe der Zahlen in einem std::array-Objekt zu berechnen, bei denen es sich um Primzahlen handelt. Die combinable-Klasse steigert die Leistung, indem sie Freigabezustand ausschließt.

Tipp Tipp

In einigen Fällen kann die parallele Zuordnung (concurrency::parallel_transform) und eine Reduzierung (concurrency::parallel_reduce) zu Leistungsverbesserungen im Vergleich zu combinable führen. Ein Beispiel, in dem Zuordnungs- und Reduzierungsoperationen verwendet werden, und das die gleichen Ergebnisse wie dieses Beispiel ergibt, finden Sie unter Parallele Algorithmen.

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 der concurrency::parallel_for_each-Algorithmus zum parallelen Verarbeiten des Arrays und ein concurrency::critical_section-Objekt zum Synchronisieren des Zugriffs auf die prime_sum-Variable verwendet. 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 verwendet, um einen Verweis auf die lokale Summe zu erhalten. Anschließend werden mit der concurrency::combinable::combine-Methode und einem std::plus-Objekt die lokalen Berechnungen zum Endergebnis zusammengefasst.

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
serielle Uhrzeit: 6178 ms

1709600813
parallele Uhrzeit: 1638 ms
              
            

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

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

Ein Beispiel, in dem Zuordnungs- und Reduzierungsoperationen verwendet werden, und das die gleichen Ergebnisse erzeugt, finden Sie unter Parallele Algorithmen.

Community-Beiträge

Anzeigen:
© 2015 Microsoft