Ho eseguito un benchmark confrontando una funzione ricorsiva rispetto a una funzione lambda ricorsiva utilizzando il std::function<>
metodo di acquisizione. Con le ottimizzazioni complete abilitate su clang versione 4.1, la versione lambda è stata notevolmente più lenta.
#include <iostream>
#include <functional>
#include <chrono>
uint64_t sum1(int n) {
return (n <= 1) ? 1 : n + sum1(n - 1);
}
std::function<uint64_t(int)> sum2 = [&] (int n) {
return (n <= 1) ? 1 : n + sum2(n - 1);
};
auto const ITERATIONS = 10000;
auto const DEPTH = 100000;
template <class Func, class Input>
void benchmark(Func&& func, Input&& input) {
auto t1 = std::chrono::high_resolution_clock::now();
for (auto i = 0; i != ITERATIONS; ++i) {
func(input);
}
auto t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count();
std::cout << "Duration: " << duration << std::endl;
}
int main() {
benchmark(sum1, DEPTH);
benchmark(sum2, DEPTH);
}
Produce risultati:
Duration: 0 // regular function
Duration: 4027 // lambda function
(Nota: ho anche confermato con una versione che ha preso gli input da cin, in modo da eliminare la valutazione del tempo di compilazione)
Clang produce anche un avviso del compilatore:
main.cc:10:29: warning: variable 'sum2' is uninitialized when used within its own initialization [-Wuninitialized]
Quale è previsto e sicuro, ma dovrebbe essere notato.
È fantastico avere una soluzione nelle nostre cinture degli strumenti, ma penso che il linguaggio avrà bisogno di un modo migliore per gestire questo caso se le prestazioni devono essere paragonabili ai metodi attuali.
Nota:
Come ha sottolineato un commentatore, sembra che l'ultima versione di VC ++ abbia trovato un modo per ottimizzarlo al punto di pari prestazioni. Forse non abbiamo bisogno di un modo migliore per gestirlo, dopo tutto (tranne per lo zucchero sintattico).
Inoltre, come alcuni altri post SO hanno delineato nelle ultime settimane, le prestazioni di per std::function<>
sé possono essere la causa del rallentamento rispetto alla funzione di chiamata direttamente, almeno quando l'acquisizione lambda è troppo grande per adattarsi ad alcuni std::function
usi dello spazio ottimizzati per le librerie per piccoli funzioni (Suppongo che in qualche modo piacciano le varie ottimizzazioni di stringhe corte?).