Share via


Cómo: Usar la clase combinable para mejorar el rendimiento

En este ejemplo se muestra cómo utilizar el concurrency::combinable clase para calcular la suma de los números en un std::array objeto que se prime.La clase combinable mejora el rendimiento eliminando el estado compartido.

SugerenciaSugerencia

En algunos casos, en paralelo mapa (concurrency::parallel_transform) y reducir (concurrencia:: parallel_reduce) puede proporcionar mejoras de rendimiento a través de combinable.Para obtener un ejemplo que utiliza se asigna y reduce las operaciones para producir los mismos resultados que en este ejemplo, consulte Algoritmos paralelos.

Ejemplo

En el siguiente ejemplo se usa la función std::accumulate para calcular la suma de los elementos de una matriz que son primos.En este ejemplo, a es un objeto array y la función is_prime determina si su valor de entrada es primo.

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

En el siguiente ejemplo se muestra una manera sencilla de ejecutar el ejemplo anterior en paralelo.Este ejemplo se utiliza la concurrency::parallel_for_each algoritmo para procesar la matriz en paralelo y un concurrency::critical_section objeto para sincronizar el acceso a la prime_sum variable.Este ejemplo no se escala porque cada subproceso debe esperar a que el recurso compartido esté disponible.

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();
});

En el siguiente ejemplo se usa un objeto combinable para mejorar el rendimiento del ejemplo anterior.En este ejemplo se elimina la necesidad de usar los objetos de sincronización; se escala porque el objeto combinable permite a cada subproceso realizar su tarea independientemente.

Un objeto combinable se usa normalmente en dos pasos.Primero, genere una serie de cálculos específicos realizando el trabajo en paralelo.Luego, combine (o reduzca) los cálculos en un resultado final.Este ejemplo se utiliza la concurrency::combinable::local método para obtener una referencia a la suma local.A continuación, utiliza el concurrency::combinable::combine método y un std::plus objeto para combinar los cálculos locales en el resultado final.

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>());

El siguiente ejemplo completo calcula la suma de números primos consecutivamente y en paralelo.El ejemplo imprime en la consola el tiempo necesario para realizar ambos cálculos.

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

La siguiente salida de ejemplo corresponde a un equipo con cuatro procesadores.

1709600813
serial time: 6178 ms

1709600813
parallel time: 1638 ms

Compilar el código

Para compilar el código, copiarlo y, a continuación, péguelo en un proyecto de Visual Studio o lo pega en un archivo denominado paralelo suma de primes.cpp y, a continuación, ejecute el siguiente comando en una ventana de símbolo del sistema de Visual Studio.

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

Programación eficaz

Para obtener un ejemplo que utiliza se asigna y reduce las operaciones para producir los mismos resultados, consulte Algoritmos paralelos.

Vea también

Referencia

Clase combinable

critical_section (Clase)

Conceptos

Contenedores y objetos paralelos