【问题标题】:Fast function objects in C++?C ++中的快速函数对象?
【发布时间】:2012-10-15 13:38:31
【问题描述】:

我正在编写一个科学计算程序,我最感兴趣的(在正确性之后)是速度。最近我注意到我也需要可读的代码。 :)

而不是写

for (int k=0;k!=10;k+=1)
   array[k] = fun(a, k);

我正在考虑写作

class fun_t {
private:
   type a;
public:
   fun_t(type in) : a(in) {};

   type operator() (int k) {
      ...computation...
   }
};
...
fun_t fun(a);
for (int k=0;k!=10;k+=1)
   array[k] = fun(k);

函数对象样式会和第一个例子一样快吗?我可以期望两者都有相同的内联吗?有没有更好的方法? (请注意,我只是在这里提出想法,这不是我的实际代码。)

【问题讨论】:

  • 从C++11开始,语言中有匿名函数(lambda)。
  • 最好的发现方法是分析。
  • @PlasmaHH:你的意思是我应该编写两个版本的程序吗?我不能要求编译器验证内联正在发生吗?
  • @Mankka:lambda 简单地编译成函子(函数对象),而函子对于编译器内联来说是微不足道的。所以它应该基本上是免费的(就像你在问题中概述的版本一样)。但一如既往,如果性能很重要,不要相信互联网上的随机人,在你的代码中衡量
  • 我很欣赏这只是一个例子,但你提到你想要可读的代码,但是你已经从两行(对我来说非常易读)变成了 10 行,实际上包括(实际上)你原来的两行。从可读性的角度来看,我会说这是一个倒退。

标签: c++ performance function object functional-programming


【解决方案1】:

我想繁重的计算是在您的函数内部执行的。相比之下,直接函数调用和成员函数调用之间的差异应该是微不足道的。

【讨论】:

  • 非常好!函数中的计算过去非常小而且很快,但现在我正在 MPI 中重构和重写,所以我不确定事情会如何发展。也许我是时候退后一步,看看大局了。
  • 是的,它只被调用了 10 次。您从内联中获得的节省是每次调用时的堆栈卷绕/展开、跳转和参数推送。这是一个相当快的操作,并且执行 10 次不太可能以任何明显的方式减慢您的程序。
【解决方案2】:

您可以从合理的编译器中获得相同的内联。对operator() 的调用的目的地在编译时是已知的,就像对fun(a,k) 的调用一样。

我看到的区别在于对a 的访问。在函数fun 的情况下,您将something 作为参数传递——如果没有fun 的声明,则无法查看这是否是a 的副本,参考a,或从 a 构造的其他类型。

在函子fun_t 的情况下,您复制a 一次以构造函子。您(名义上)将fun_t* 作为this 传递给operator(),然后a 作为this->a 访问。一旦所有内容都被内联并且优化器完成后,额外的间接可能会被忽略,但同样可能不会。您必须检查具体情况,可能通过检查编译器发出的指令。

【讨论】:

    【解决方案3】:

    您可以通过更改循环结构进行一些小的优化,但这些优化的主要目的不是为了提高速度。

    如果您想提高速度,您需要进行分析。如果fun(a,k) 特别是一个缓慢的操作,并且每次运行不依赖于其他运行,您应该考虑拆分成线程并在自己的线程上运行每个线程。

    有新的 API 将并行而不是串行地对集合进行操作。激动人心的时刻即将到来。

    【讨论】:

    • 你是什么意思,“有新的 API 来了”? C++11 已经存在一年了!
    • 明确一点:我同意分析是使代码更快的#1 解决方案。如果分析证明您想要优化循环,则矢量化和并行化是一个明显的解决方案。
    • @KlassvanGend 将在您的编译器/标准库中实际实现。
    猜你喜欢
    • 1970-01-01
    • 2012-08-13
    • 2017-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    相关资源
    最近更新 更多