2011-12-23 12 views
22

Acabo de tratar de comparar el rendimiento de las expresiones lambda en C++ 11, así que hice la prueba: calculo la suma de elementos en un vector de valores double. Aquí está la aplicación:¿Por qué C++ lambda es más lento que la función común cuando se llama varias veces?

#include <vector> 
#include <algorithm> 
#include <iostream> 
#include <ctime> 

#define LOG(x) { std::cout << #x << " = " << (x) << "\n"; } 
#define TIME(t) { std::cout << ((double)(clock() - (t))/CLOCKS_PER_SEC) << " s\n"; } 

double sum(const std::vector<double>& v) 
{ 
    double s = 0.0; 
    for (auto i = v.cbegin(); i != v.cend(); ++i) 
     s += *i; 
    return s; 
} 

int main() 
{ 
    const size_t MAX = 1; // number of tests 
    const size_t SIZE = 100000000; // length of the vector 

    std::vector<double> v(SIZE, 1.0); 
    double out; 

    clock_t clk; 

    std::cout << "iterator\n"; 

    clk = clock(); 
    out = 0.0; 
    for (size_t i = 0; i < MAX; ++i) 
     out += sum(v); 
    TIME(clk) 
    LOG(out) 

    std::cout << "\nlambda\n"; 

    clk = clock(); 
    out = 0.0; 
    for (size_t i = 0; i < MAX; ++i) 
     std::for_each(v.cbegin(), v.cend(), [&](double d) { out += d; }); 
    TIME(clk) 
    LOG(out) 

    return 0; 
} 

aquí es el resultado de este programa (compilado en VS2010 SP1, en modo de lanzamiento):

 
iterator 
0.32 s 
out = 1e+008 

lambda 
0.326 s 
out = 1e+008 

Como se puede ver, no hay prácticamente ninguna diferencia en el rendimiento. Sin embargo, si Doy 10 como el valor de MAX (que significa la suma se realiza 10 veces en lugar de uno), los resultados difieren:

 
iterator 
0.287 s 
out = 1e+009 

lambda 
2.84 s 
out = 1e+009 

de prueba para la expresión lambda tomó aproximadamente 10 veces más tiempo. ¿Por qué? Pensé que puede ser causado por el hecho de que en cada iteración nueva lambda se crea, pero afilare He intentado esto:

out = 0.0; 
auto f = [&](double d) { out += d; }; 
for (size_t i = 0; i < MAX; ++i) 
    std::for_each(v.cbegin(), v.cend(), f); 

los resultados no habían cambiado. ¿Podría alguien explicarme ese comportamiento?

+2

¡Esto es muy intrigante! ¿Podría intentar usar lambda en un bucle escrito a mano en lugar de 'foreach'? – dasblinkenlight

+0

g ++ 4.6.2 en Linux proporciona tiempos de ejecución exactamente idénticos (0.13 - 0.12 s en mi computadora) – Cubbi

+0

No más misterio, verifique mi edición. Mi error, pero aún así lo encuentro bastante interesante. :) – Archie

Respuesta

39

Resultó que no hay ningún problema con las expresiones lambda, solo el compilador optimizó el bucle externo en el primer caso al almacenar en caché el resultado de la función sum(). Después de cambiar el primer caso a este formulario:

out = 0.0; 
for (size_t i = 0; i < MAX; ++i) 
{ 
    out += sum(v); 
    v[i] = 1.0; // this adds O(1) time and prevents caching 
} 

Ambos casos son aproximadamente iguales, con lambda como favorito.

+9

Buena investigación. –

+3

Y la moraleja de la historia: siempre pruebe y comparta con el código * real *, nunca con el código * toy *. –

+2

@Archie ¿También agregó la v [i] = 1.0 a la lambda también? – sprite

Cuestiones relacionadas