【问题标题】:Auto in loop and optimizations自动循环和优化
【发布时间】:2013-06-12 11:46:02
【问题描述】:

您能解释一下为什么使用以下代码(未优化)的计算时间存在如此大的差异。我怀疑 RVO 与 move-construction,但我不太确定。

一般来说,遇到这种情况时最好的做法是什么?初始化非 POD 数据时,循环中的自动声明是否被视为不好的做法?

在循环内使用 auto :

std::vector<int> foo()
{
    return {1,2,3,4,5};
}

int main()
{
    for (size_t i = 0; i < 1000000; ++i)
        auto f = foo();
    return 0; 
}

输出:

./a.out 0.17s user 0.00s system 97% cpu 0.177 total

循环外的向量实例:

std::vector<int> foo()
{
    return {1,2,3,4,5};
}

int main()
{
    std::vector<int> f;

    for (size_t i = 0; i < 1000000; ++i)
         f = foo();
    return 0;
}

输出:

./a.out 0.32s user 0.00s system 99% cpu 0.325 total

【问题讨论】:

  • 在一个循环中有声明和初始化,而在另一个循环中只有一个赋值。这是故意的吗?如果您将橙子与橙子进行比较,您不应该在循环内移动 std::vector&lt;int&gt; f 吗?
  • 如果您怀疑移动构造要快得多,请使用您自己的向量类,将移动构造函数转发给复制构造函数,然后再次测量。或者查看程序集,看看它在做什么。或者在你的类的复制/移动构造函数和赋值运算符中添加计数器,看看实际调用了什么。
  • 另外:虚假基准警报。任何具有良好优化“技能”的编译器都可以优化所有循环
  • 没有优化的“基准”毫无意义。
  • 让我猜猜:您测量的是调试版本还是未优化版本?

标签: c++ loops optimization c++11 auto


【解决方案1】:

我怀疑 RVO 与 move-construction,但我不太确定。

是的,几乎可以肯定正在发生的事情。第一种情况是从函数的返回值中移动初始化一个变量:在这种情况下,可以通过使函数在适当的位置初始化它来省略移动。第二种情况从返回值移动赋值;任务不能省略。我相信 GCC 即使在优化级别为零时也会执行省略,除非您明确禁用它。

在最后一种情况下(-O3,现在已从问题中删除)编译器可能会注意到循环没有副作用,并将其完全删除。

通过声明向量volatile 并进行优化编译,您可能(或可能不会)获得更有用的基准。这将强制编译器在每次迭代时实际创建/分配它,即使它认为它知道得更好。

在初始化非 POD 数据时,循环中的自动声明是否被视为不好的做法?

没有;如果有的话,在所需的最窄范围内声明事物被认为是更好的做法。因此,如果只在循环中需要它,请在循环中声明它。在某些情况下,您可以通过在循环外声明一个复杂对象来避免在每次迭代中重新创建它,从而获得更好的性能;但只有在您确定性能优势 (a) 存在并且 (b) 值得失去局部性时才这样做。

【讨论】:

  • 谢谢!非常有用,尤其是最后一句话:)
【解决方案2】:

我认为您的示例与auto 没有任何关系。你编写了两个不同的程序。

虽然

for (size_t i = 0; i < 1000000; ++i)
    auto f = foo();

等价于

for (size_t i = 0; i < 1000000; ++i)
    std::vector<int> f = foo();

-- 这意味着,您创建一个新向量(并销毁旧向量)。而且,是的,在您使用 RVO 的foo 实现中,但这不是重点:您仍然在外循环为f 腾出空间的地方创建一个新的vector

sn-p

std::vector<int> f;
for (size_t i = 0; i < 1000000; ++i)
     f = foo();

使用 assign 到现有向量。而且,是的,使用 RVO,它可能会变成 move-assign,具体取决于 foo,这就是你的情况,所以你可以期待它很快。但它仍然不同的东西——它始终是负责管理资源的f

但是你在这里非常漂亮地展示了遵循一般规则通常是有意义的

声明变量尽可能接近它们的用途。

this Discussion

【讨论】:

    猜你喜欢
    • 2014-11-09
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 2017-07-20
    相关资源
    最近更新 更多