为什么提升::功能很慢
Why is boost::function slow?
我正在做一些定时测试,我的测试之一是比较调用函数的不同方式。我使用各种方法调用了 N 个函数。我尝试了常规函数调用、虚拟函数调用、函数指针和 boost::function。
我在 Linux 中使用 gcc 和 -O3 优化来做到这一点。
正如预期的那样,虚拟调用比常规函数调用慢。然而,令人惊讶的是,boost::函数的时钟速度比虚拟调用慢 33%。
还有其他人注意到这一点吗?有什么线索可以理解为什么会这样吗?
如果可能的话,编译器可以内联常规函数,但boost::function
永远不能内联。这是一个很大的区别。
第二个区别是,boost::function
实现了类型擦除,这意味着它使用间接寻址来调用实际函数。意味着它首先调用一个虚拟函数,然后调用你的函数。所以通常它涉及(最少)两个函数调用(其中一个是virtual
)。这是巨大的差异。
因此,基于此分析,可以推断出这一点(甚至无需编写测试代码):
slowest ------------------------------------------------------> fastest
boost::function < virtual function < regular function
slowest ------------------------------------------------------> fastest
在您的测试代码中确实如此。
请注意,std::function
也是如此(自 C++11 起可用)。
boost::function
不仅可以保存函数指针,还可以保存任意对象的整个副本,它调用可能的虚拟operator()
。
可以帮助了解它是如何工作的(用于阐述)。
下面是一个boost::function
型技巧的玩具实现:
struct helper_base { virtual void do_it() = 0; };
template<typename Func>
struct helper:helper_base {
Func func;
helper(Func f):func(f) {}
virtual void do_it() override { func(); }
};
struct do_something_later {
boost::unique_ptr<helper_base> pImpl;
template<typename Func>
do_something_later( Func f ):pImpl(make_shared<helper<Func>>(f))
{}
void operator()() { (*pImpl).do_it(); }
private:
do_something_later( do_something_later const& ); // deleted
void operator=( do_something_later const& ); // deleted
};
在这里,我的do_something_later
获取一个任意对象(Func)并按需调用operator()
。 它将我们正在调用operator()
的东西的类型包装在类型纠删助手中,然后通过虚拟函数调用operator()
。
Func
类型可以是函数指针,也可以是带有状态的函子。 任何可以使用 operator() 复制的东西都是公平的游戏。 就do_something_later
的用户而言,只有一个二进制接口。
boost::function
(和std::function
)使用基本相同的技术(有很多改进)将一整套可能的接口转换为一个接口。 成本涉及调用virtual
函数(或等效的间接级别)。
观察到缓慢的真正原因是,除了两个间接寻址之外,boost::function
将指针与零进行比较。如果省略此测试,则调用的执行速度将与虚拟函数一样快(这也涉及两个间接 - 一个指向 vtable 的指针,另一个指向实际函数的指针)。
- 为什么我的功能在使用 goto 时会给我带来"expected primary-expression before '}' token"?
- 为什么每当我尝试运行此链接列表删除功能时都会收到分段错误错误?
- 为什么我不能拥有某些私有会员功能?
- 为什么我的打印功能不起作用?链表
- 为什么我的显示功能会终止程序?
- 为什么从基转换为派生提供此功能?
- 为什么__builtin_popcount比我自己的比特计数功能慢?
- 为什么 C++ 标准库中没有 SIMD 功能?
- 为什么在功能内擦除元素后不列出更新?
- 为什么我无法覆盖虚拟功能?
- 为什么必须动态分配扩展数组才能使此功能正常工作C++
- 为什么我无法使用push_back功能?
- C++ 为什么const X&可以通过功能进行修改?
- 为什么以下 POP 功能无法在主机或设备 (CUDA) 上运行?
- 为什么我的删除功能总是出现分段错误
- 如果在创建对象时创建了 VPTR,那么为什么具有虚拟功能的类的大小在 32 位系统上为 4,在 64 位机器上为 8
- 为什么Visual Studio无法识别is_open()功能
- 使用链表.为什么我的插入功能不起作用?
- 为什么虚拟继承即使不涉及虚拟功能也需要 vtable?
- 我正在使用放置新功能和虚拟功能;为什么我的虚拟功能表有误?