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

我们假设:

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

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

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

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


当前回答

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

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?

其他回答

添加这个答案,因为我没有看到它包括在所有其他。

最小化类型和符号之间的隐式转换:

这至少适用于C/ c++,即使你已经认为你已经摆脱了转换——有时测试在需要性能的函数周围添加编译器警告是很好的,特别是注意循环中的转换。

特定于GCC:您可以通过在代码周围添加一些冗长的pragmas来测试这一点,

#ifdef __GNUC__
#  pragma GCC diagnostic push
#  pragma GCC diagnostic error "-Wsign-conversion"
#  pragma GCC diagnostic error "-Wdouble-promotion"
#  pragma GCC diagnostic error "-Wsign-compare"
#  pragma GCC diagnostic error "-Wconversion"
#endif

/* your code */

#ifdef __GNUC__
#  pragma GCC diagnostic pop
#endif

我曾见过一些案例,你可以通过减少这样的警告所带来的转化率来获得几个百分点的加速。

在某些情况下,我有一个带有严格警告的头,我保留了这些警告,以防止意外转换,然而这是一种权衡,因为您可能最终会为安静的故意转换添加大量强制转换,这可能会使代码更加混乱,而收益却微乎其微。

由于许多性能问题都涉及数据库问题,因此在调优查询和存储过程时,我将介绍一些需要注意的具体问题。

避免在大多数数据库中使用游标。也要避免循环。大多数时候,数据访问应该基于设置,而不是逐条记录处理。这包括当您希望一次插入1,000,000条记录时,不要重用单个记录存储过程。

不要使用select *,只返回实际需要的字段。如果存在任何连接,则尤其如此,因为连接字段将重复,从而在服务器和网络上造成不必要的负载。

避免使用相关的子查询。使用连接(尽可能包括到派生表的连接)(我知道这对于Microsoft SQL Server是正确的,但是在使用不同的后端时测试建议)。

索引,索引,索引。如果适用于您的数据库,请更新这些统计数据。

使查询sargable。这意味着避免一些不可能使用索引的事情,例如在like子句的第一个字符中使用通配符,或在join中的函数中使用通配符,或作为where语句的左侧部分。

使用正确的数据类型。在日期字段上进行日期计算要比尝试将字符串数据类型转换为日期数据类型然后进行计算快得多。

永远不要在触发器中放入任何形式的循环!

大多数数据库都有一种方法来检查如何执行查询。在Microsoft SQL Server中,这被称为执行计划。先检查一下,看看问题出在哪里。

在确定需要优化的内容时,考虑查询运行的频率以及运行所需的时间。有时,对一个每天运行数百万次的查询稍作调整,可以获得比删除一个月只运行一次的long_running查询更多的性能。

使用某种分析器工具来找出发送到数据库和从数据库发送的内容。我记得过去有一次,我们不知道为什么页面加载这么慢,而存储过程却很快,并通过分析发现网页多次而不是一次地请求查询。

剖析器还将帮助您找到谁在阻止谁。一些单独运行时执行很快的查询可能会因为来自其他查询的锁而变得非常慢。

分而治之

如果正在处理的数据集太大,则对其中的大块进行循环。如果代码编写正确,实现应该很容易。如果您有一个单片程序,现在您就更清楚了。

您可能应该考虑“谷歌视角”,即确定您的应用程序如何在很大程度上实现并行和并发,这也不可避免地意味着在某种程度上考虑将您的应用程序分布在不同的机器和网络上,这样它就可以理想地与您投入的硬件几乎线性扩展。

另一方面,谷歌人员也以投入大量人力和资源来解决他们正在使用的项目、工具和基础设施中的一些问题而闻名,例如,通过拥有一个专门的工程师团队来破解gcc内部,以便为Google典型的用例场景做好准备,从而对gcc进行整个程序优化。

类似地,分析应用程序不再仅仅意味着分析程序代码,还包括它周围的所有系统和基础设施(想想网络、交换机、服务器、RAID阵列),以便从系统的角度识别冗余和优化潜力。

建议:

Pre-compute rather than re-calculate: any loops or repeated calls that contain calculations that have a relatively limited range of inputs, consider making a lookup (array or dictionary) that contains the result of that calculation for all values in the valid range of inputs. Then use a simple lookup inside the algorithm instead. Down-sides: if few of the pre-computed values are actually used this may make matters worse, also the lookup may take significant memory. Don't use library methods: most libraries need to be written to operate correctly under a broad range of scenarios, and perform null checks on parameters, etc. By re-implementing a method you may be able to strip out a lot of logic that does not apply in the exact circumstance you are using it. Down-sides: writing additional code means more surface area for bugs. Do use library methods: to contradict myself, language libraries get written by people that are a lot smarter than you or me; odds are they did it better and faster. Do not implement it yourself unless you can actually make it faster (i.e.: always measure!) Cheat: in some cases although an exact calculation may exist for your problem, you may not need 'exact', sometimes an approximation may be 'good enough' and a lot faster in the deal. Ask yourself, does it really matter if the answer is out by 1%? 5%? even 10%? Down-sides: Well... the answer won't be exact.