在这个网站上已经有很多性能问题了,但是在我看来,几乎所有的问题都是非常具体的,而且相当狭窄。几乎所有人都重复了避免过早优化的建议。

我们假设:

代码已经正常工作了 所选择的算法对于问题的环境已经是最优的 对代码进行了测量,并隔离了有问题的例程 所有优化的尝试也将被衡量,以确保它们不会使事情变得更糟

我在这里寻找的是策略和技巧,在一个关键算法中,当没有其他事情可做,但无论如何都要挤出最后百分之几。

理想情况下,尽量让答案与语言无关,并在适用的情况下指出所建议的策略的任何缺点。

我将添加一个带有我自己最初建议的回复,并期待Stack Overflow社区能想到的任何其他东西。


当前回答

不像之前的答案那么深入或复杂,但下面是: (这些更多是初级/中级水平)

明显:干 向后运行循环,所以总是与0比较,而不是与变量比较 尽可能使用位操作符 将重复的代码分解为模块/函数 缓存对象 局部变量具有轻微的性能优势 尽可能限制字符串操作

其他回答

如果更好的硬件是一个选择,那么一定要去做。否则

Check you are using the best compiler and linker options. If hotspot routine in different library to frequent caller, consider moving or cloning it to the callers module. Eliminates some of the call overhead and may improve cache hits (cf how AIX links strcpy() statically into separately linked shared objects). This could of course decrease cache hits also, which is why one measure. See if there is any possibility of using a specialized version of the hotspot routine. Downside is more than one version to maintain. Look at the assembler. If you think it could be better, consider why the compiler did not figure this out, and how you could help the compiler. Consider: are you really using the best algorithm? Is it the best algorithm for your input size?

我大半辈子都在这里度过。大致的方法是运行你的分析器并记录它:

Cache misses. Data cache is the #1 source of stalls in most programs. Improve cache hit rate by reorganizing offending data structures to have better locality; pack structures and numerical types down to eliminate wasted bytes (and therefore wasted cache fetches); prefetch data wherever possible to reduce stalls. Load-hit-stores. Compiler assumptions about pointer aliasing, and cases where data is moved between disconnected register sets via memory, can cause a certain pathological behavior that causes the entire CPU pipeline to clear on a load op. Find places where floats, vectors, and ints are being cast to one another and eliminate them. Use __restrict liberally to promise the compiler about aliasing. Microcoded operations. Most processors have some operations that cannot be pipelined, but instead run a tiny subroutine stored in ROM. Examples on the PowerPC are integer multiply, divide, and shift-by-variable-amount. The problem is that the entire pipeline stops dead while this operation is executing. Try to eliminate use of these operations or at least break them down into their constituent pipelined ops so you can get the benefit of superscalar dispatch on whatever the rest of your program is doing. Branch mispredicts. These too empty the pipeline. Find cases where the CPU is spending a lot of time refilling the pipe after a branch, and use branch hinting if available to get it to predict correctly more often. Or better yet, replace branches with conditional-moves wherever possible, especially after floating point operations because their pipe is usually deeper and reading the condition flags after fcmp can cause a stall. Sequential floating-point ops. Make these SIMD.

我还喜欢做一件事:

将编译器设置为输出程序集清单,并查看它为代码中的热点函数发出了什么。所有那些聪明的优化,“一个好的编译器应该能够自动为你做”?实际的编译器可能不会执行这些操作。我见过GCC发出真正的WTF代码。

如果你有很多高度并行的浮点运算——尤其是单精度运算——尝试使用OpenCL或(对于NVidia芯片)CUDA将其卸载到图形处理器上(如果有的话)。gpu在着色器中拥有强大的浮点计算能力,这比CPU要大得多。

缓存!要使几乎任何事情都变得更快,一个便宜的方法(在程序员的努力中)是在程序的任何数据移动区域添加缓存抽象层。无论是I/O还是只是传递/创建对象或结构。通常,向工厂类和读取器/写入器添加缓存是很容易的。

有时缓存不会给你带来太多好处,但这是一种简单的方法,只需添加缓存,然后在没有帮助的地方禁用它。我经常发现这样做可以获得巨大的性能,而无需对代码进行微观分析。

你在什么硬件上运行?您是否可以使用特定于平台化的优化(如向量化)? 你能找到更好的编译器吗?比如从GCC换成Intel? 你能让你的算法并行运行吗? 可以通过重新组织数据来减少缓存丢失吗? 可以禁用断言吗? 对编译器和平台进行微优化。在if/else语句中,把最常见的语句放在前面