C++:几种callable实现方式的性能对比
2017-10-31 20:51 付哲 阅读(2834) 评论(0) 编辑 收藏 举报C++中几种callable实现方式的性能对比
前言
C++中想实现一个callable的对象,通常有四种方式:
std::function
:最common的方式,一般会配合std::bind
使用。- function pointer:最C的方式,但没办法实现有状态的callable object。
- function object:就是重载了
operator()
的类,C++98的STL中经常用。 - lambda expression:不会污染namespace,一般来说编译器内部会实现为一个匿名的function object。
从原理上性能最好的应该是3和4,其次是2,最差的是std::function
。下面我们用一小段代码来测试它们的性能。
测试结果
- 测试机器:15' rMBP。
- 编译器:Apple LLVM version 8.1.0 (clang-802.0.42)。
- 编译方式:g++ test.cpp -std=c++14 -O2。
./a.out "std::function" 0.15s user 0.20s system 98% cpu 0.358 total
./a.out "function_pointer" 0.10s user 0.11s system 98% cpu 0.209 total
./a.out "function_object" 0.03s user 0.01s system 92% cpu 0.042 total
./a.out "lambda" 0.03s user 0.01s system 93% cpu 0.042 total
可以看到3和4只要42ms,而相对应的2需要209ms,1需要358ms。这个顺序符合我们的预期,但相差这么多还是比较意外的。
测试程序
#include <iostream>
#include <functional>
#include <vector>
#include <string>
#include <utility>
using namespace std;
template <typename HandlerT = std::function<void (int)>>
class Worker{
public:
explicit Worker(const HandlerT& handler): mHandler(handler) {}
void Run(int x) {
mHandler(x);
}
private:
HandlerT mHandler;
};
template <typename HandlerT>
void Test(HandlerT&& h) {
using WorkerT = Worker<HandlerT>;
vector<WorkerT> v;
for (int i = 0; i < 10000000; ++i) {
v.emplace_back(std::forward<HandlerT>(h));
}
int j = 0;
for (auto& w: v) {
w.Run(++j);
}
}
void Func(int x) {
int y = x + 5;
y += 3;
}
struct Functor {
void operator()(int x) const {
int y = x + 5;
y += 3;
}
};
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "error input" << endl;
exit(1);
}
string mode{argv[1]};
if (mode == "std::function") {
Test(bind(Func, placeholders::_1));
} else if (mode == "function_pointer") {
Test(Func);
} else if (mode == "function_object") {
Test(Functor{});
} else if (mode == "lambda") {
Test([](int x) -> void {int y = x + 5; y += 3;});
} else {
cerr << "error mode:" << mode << endl;
exit(1);
}
}