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