Я провел бенчмарк, сравнивая рекурсивную функцию с рекурсивной лямбда-функцией, используя метод захвата std::function<>
. С полной оптимизацией, включенной в версии 4.1 clang, лямбда-версия работала значительно медленнее.
#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);
}
Производит результаты:
Duration: 0 // regular function
Duration: 4027 // lambda function
(Примечание: я также подтвердил версию, которая взяла входные данные от cin, чтобы исключить оценку времени компиляции)
Clang также выдает предупреждение компилятора:
main.cc:10:29: warning: variable 'sum2' is uninitialized when used within its own initialization [-Wuninitialized]
Что ожидается и безопасно, но следует отметить.
Здорово иметь решение в наших инструментальных наборах, но я думаю, что языку понадобится лучший способ справиться с этим случаем, если производительность должна быть сопоставима с современными методами.
Примечание:
Как отметил комментатор, похоже, что последняя версия VC ++ нашла способ оптимизировать это до уровня равной производительности. Возможно, в конце концов нам не нужен лучший способ справиться с этим (за исключением синтаксического сахара).
Кроме того, как отмечали некоторые другие сообщения SO в последние недели, производительность самого std::function<>
может быть причиной замедления по сравнению с непосредственным вызовом функции, по крайней мере, когда лямбда-захват слишком велик, чтобы поместиться в оптимизированную библиотеку пробел std::function
используется для маленьких функторов (я думаю, что они похожи на различные оптимизации коротких строк?).