2011-12-23 16 views
22

Po prostu próbowałem porównać wydajność wyrażeń lambda w C++ 11, więc wykonałem test - obliczono sumę elementów w wektorze o wartościach double. Oto realizacja:Dlaczego lambda C++ jest wolniejsza niż zwykła funkcja, gdy jest wywoływana wiele razy?

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

Oto wynik tego programu (sporządzoną VS2010 SP1, w trybie wydania):

 
iterator 
0.32 s 
out = 1e+008 

lambda 
0.326 s 
out = 1e+008 

Jak widać, nie ma praktycznie żadnej różnicy w wydajności. , Jeśli otrzymując 10 jako wartość MAX (oznacza to sumowanie zostanie przeprowadzone 10 razy zamiast jednego), jednakże może być różne:

 
iterator 
0.287 s 
out = 1e+009 

lambda 
2.84 s 
out = 1e+009 

zbadania ekspresji lambda trwało około 10 razy więcej czasu. Czemu? Myślałem, że może to być spowodowane faktem, że w każdej iteracji nowego lambda jest tworzony, ale zaostrzy Próbowałem to:

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

wyniki nie uległy zmianie. Czy ktoś mógłby mi wytłumaczyć to zachowanie?

+2

To bardzo intrygujące! Czy mógłbyś spróbować użyć lambda w ręcznie pisanej pętli zamiast 'foreach'? – dasblinkenlight

+0

g ++ 4.6.2 na Linuxie daje dokładnie identyczne czasy uruchamiania (0.13 - 0.12 s na moim komputerze) – Cubbi

+0

Koniec z tajemnicą, sprawdź moją edycję. Mój błąd, ale nadal uważam, że jest całkiem interesujący. :) – Archie

Odpowiedz

39

Okazało się, że nie jest to problem z wyrażeniami lambda, tylko kompilator zoptymalizował zewnętrzną pętlę w pierwszym przypadku przez buforowanie wyniku funkcji sum(). Po zmianie pierwszego przypadku do tego formularza:

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 
} 

czasy obu przypadków są w przybliżeniu równe, a lambda jako ulubiona.

+9

Niezłe dochodzenie. –

+3

A morał z historii - zawsze testuj i porównuj z * prawdziwym * kodem, nigdy z kodem * zabawki *. –

+2

@Archie Czy dodałeś również v [i] = 1.0 do lambda? – sprite

Powiązane problemy