Vorgehensweise: Schreiben einer parallel_for_each Schleife

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

Beispiel

Im folgenden Beispiel wird die Anzahl von Primzahlen in einem Array zweimal berechnet. Im Beispiel wird zunächst der std::for_each Algorithmus verwendet, um die Anzahl fortlaufend zu berechnen. 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;

// Returns the number of milliseconds that it takes to call the passed in function.
template <class Function>
__int64 time_call(Function&& f)
{
    __int64 begin = GetTickCount();
    f();
    return GetTickCount() - begin;
}

// Determines whether the input is a prime.
bool is_prime(int n)
{
    if (n < 2)
    {
        return false;
    }

    for (int i = 2; i < int(std::sqrt(n)) + 1; ++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(begin(a), end(a), [&]
        {
            return n++;
        });

    // Use the for_each algorithm to count, serially, the number
    // of prime numbers in the array.
    LONG prime_count = 0L;
    __int64 elapsed = time_call([&]
        {
            for_each(begin(a), end(a), [&](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, in parallel, the number
    // of prime numbers in the array.
    prime_count = 0L;
    elapsed = time_call([&]
        {
            parallel_for_each(begin(a), end(a), [&](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 ist für einen Computer mit vier Kernen vorgesehen.

serial version:
found 17984 prime numbers
took 125 ms

parallel version:
found 17984 prime numbers
took 63 ms

Kompilieren des Codes

Um den Code zu kompilieren, kopieren Sie ihn, und fügen Sie ihn dann in ein Visual Studio-Projekt ein, oder fügen Sie ihn in eine Datei ein, die benannt parallel-count-primes.cpp ist, und führen Sie dann den folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster aus.

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

Stabile Programmierung

Der Lambdaausdruck, 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 sperrfreien Synchronisierungsmechanismus verwenden, z. B. die concurrency::combinable Klasse, um gleichzeitigen Zugriff auf freigegebene Ressourcen zu vermeiden. Ein Beispiel, das die combinable Klasse auf diese Weise verwendet, finden Sie unter How to: Use combinable to improve performance.

Siehe auch

Parallele Algorithmen
parallel_for_each Funktion