3

底线:速度很重要。

我查看了我的代码,并决定寻找更多方法来提高它的效率(即使提高一毫秒,那也很棒)。所有这些数据成员、方法、无用的数据创建——我们都被教导要遵循指导方针以及如何去做和不去做。

除了循环。

我们总是被鼓励使用它们,因为它们有助于提高代码的可读性并帮助用户。用户。在我说出我脑海中的定义之后,我想到了这个想法:

for (int i = 0; i < 100; i++)
{
    //whatever code
}

让我们假设我们知道长度的情况。这将执行代码 100 次,但它执行了 201 次可以省略以帮助机器的操作。如果我们复制粘贴代码 100 次,丢掉初始化、条件和终止会怎样:

//Code[0]
//Code[1]
//Code[2]
//...

这是一点点,但仍然...

这是效率狂人的常见做法吗?

4

1 回答 1

3

这是一种称为循环展开的常见优化,一个好的编译器应该会自动为您完成。根据代码,许多编译器实际上也会展开没有绝对上限的循环。

举个极端的例子,你可能对Duff 的 device感兴趣。这允许您在具有变量上限的循环上展开循环,而不必担心最后的“剩余”迭代。

如果您从 0 循环到 200,将循环展开 200x 不一定会提高您的性能。在生成多少代码和通过避免分支获得多少性能提升之间需要权衡取舍。我认为在很多代码中展开超过 10 个并不常见——但我没有任何引用来支持这个数字。

当今最常见的台式机笔记本电脑都运行 x86_64 处理器,这是一种超标量架构,可以执行诸如乱序执行和分支预测之类的疯狂事情。在你的编译器可以做的所有疯狂的事情和你的 CPU 正在做的所有疯狂的事情之间,没有太多需要手动调整这样的小事情。

实际上,您需要小心过度优化。我已经进行了很多实验,其中编译-O3而不是-O2实际减慢了我的应用程序而不是加快了它的速度。我还使用 LLVM 进行了一组实验,在其中测试了相同代码(常见的编译器基准测试)在打开和关闭单个优化时的性能如何变化。对于-O2集合之外的大多数优化,优化带来的伤害和帮助一样多。您确实需要使用您的特定应用程序测试优化,看看它们是否会有所帮助或伤害。

但是,您通常通过选择正确的数据结构和算法来获得最大的性能,而不是像这样的一点点优化。我发现最好采用以下优化方法:

  1. 编写代码使其可读。
  2. 分析代码以查看哪个部分占用的时间最多。
  3. 看看我是否可以对该部分进行算法/数据结构更改以加快速度。
  4. 当所有其他方法都失败时,请使用这种类型的低级代码转换(您希望编译器会为您处理)。
于 2013-06-29T03:26:50.840 回答