Compartir vía


Procedimiento para escribir un bucle parallel_for_each

En este ejemplo se muestra cómo usar el algoritmo concurrency::parallel_for_each para calcular el recuento de números primos en un objeto std::array en paralelo.

Ejemplo

En el siguiente ejemplo se calcula dos veces el recuento de números primos en una matriz. En el ejemplo se usa primero el algoritmo std::for_each para calcular el recuento en serie. A continuación, en el ejemplo se usa el algoritmo parallel_for_each para realizar la misma tarea en paralelo. También se imprime en la consola el tiempo necesario para realizar ambos cálculos.

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

La siguiente salida de ejemplo se corresponde a un equipo con cuatro núcleos.

serial version:
found 17984 prime numbers
took 125 ms

parallel version:
found 17984 prime numbers
took 63 ms

Compilar el código

Para compilar el código, cópielo y péguelo en un proyecto de Visual Studio, o en un archivo denominado parallel-count-primes.cpp. Después, ejecute el comando siguiente en una ventana del símbolo del sistema de Visual Studio.

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

Programación sólida

La expresión lambda que el ejemplo pasa al algoritmo parallel_for_each usa la función InterlockedIncrement para permitir a las iteraciones paralelas del bucle incrementar el contador simultáneamente. Si usa funciones como InterlockedIncrement para sincronizar el acceso a los recursos compartidos, pueden presentarse cuellos de botella de rendimiento en el código. Puede usar un mecanismo de sincronización sin bloqueos, por ejemplo, la clase concurrency::combinable, para eliminar el acceso simultáneo a los recursos compartidos. Para obtener un ejemplo en el que se usa la clase combinable de esta manera, vea Procedimiento para usar combinable para mejorar el rendimiento.

Consulte también

Algoritmos paralelos
Función parallel_for_each