J'ai exécuté un benchmark comparant une fonction récursive à une fonction lambda récursive en utilisant la std::function<>
méthode de capture. Avec des optimisations complètes activées sur la version 4.1 de clang, la version lambda fonctionnait beaucoup plus lentement.
#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);
}
Produit des résultats:
Duration: 0 // regular function
Duration: 4027 // lambda function
(Remarque: j'ai également confirmé avec une version qui prenait les entrées de cin, afin d'éliminer l'évaluation du temps de compilation)
Clang produit également un avertissement du compilateur:
main.cc:10:29: warning: variable 'sum2' is uninitialized when used within its own initialization [-Wuninitialized]
Ce qui est attendu et sûr, mais doit être noté.
C'est formidable d'avoir une solution dans nos ceintures d'outils, mais je pense que le langage aura besoin d'une meilleure façon de gérer ce cas si les performances doivent être comparables aux méthodes actuelles.
Remarque:
Comme l'a souligné un commentateur, il semble que la dernière version de VC ++ a trouvé un moyen d'optimiser cela au point de performances égales. Peut-être n'avons-nous pas besoin d'une meilleure façon de gérer cela, après tout (sauf pour le sucre syntaxique).
De plus, comme certains autres articles SO l'ont souligné ces dernières semaines, les performances en elles- std::function<>
mêmes peuvent être la cause du ralentissement par rapport à la fonction d'appel directement, du moins lorsque la capture lambda est trop grande pour s'adapter à certaines std::function
utilisations de l' espace optimisé par la bibliothèque pour les petits foncteurs. (Je suppose qu'un peu comme les diverses optimisations de chaînes courtes?).