优化代码有两个步骤。
首先,您需要找出慢的原因。这就是分析,正如您可能猜到的,分析器通常用于此目的。大多数分析器通常易于使用。您通过分析器运行您的应用程序,当它终止时,分析器将显示在每个函数中花费了多少时间,独占(此函数不计算从该函数调用的函数中花费的时间)以及包含(在此中花费的时间)函数,包括子函数调用)。
换句话说,你得到一个很大的调用树,你只需要寻找大数字。通常,很少有函数消耗超过 10% 的执行时间。所以找到这些,你就知道要优化什么了。
请注意,分析器既不是必需的,也不一定是最佳方法。一个非常简单但有效的方法是在调试器中运行程序,并在几个准随机时间暂停执行并查看调用堆栈。只做几次,你就会非常清楚你的执行时间花在了哪里。在此答案下发表评论的@Mike Dunlavey 在其他地方深入描述了这种方法。
但既然您知道执行时间花在哪里了,那么棘手的部分就来了,如何优化代码。
当然,最有效的方法通常是高级方法。问题一定要这样解决吗?它必须解决吗?是否可以提前解决并缓存结果,以便在应用程序的其余部分需要时立即交付?
有没有更有效的算法来解决这个问题?
如果您可以应用此类高级优化,请执行此操作,看看是否充分提高了性能,如果没有,请再次分析。
迟早,您可能需要深入研究更底层的优化。不过,这是一个棘手的领域。今天的计算机非常复杂,您从中获得的性能并不简单。分支或函数调用的成本可能因上下文而异。将两个数字加在一起可能需要 0 到 100 个时钟周期,具体取决于这两个值是否已经在 CPU 的寄存器中、当时正在执行的 else 以及许多其他因素。因此,此级别的优化需要 (1) 充分了解 CPU 的工作原理,以及 (2) 大量的实验和测量。您可以轻松地做出您认为会更快的更改,但您需要确定,因此请测量更改前后的性能。
有一些一般的经验法则通常可以帮助指导优化:
I/O 很昂贵。 CPU 指令以几分之一纳秒为单位进行测量。 RAM 访问大约为几十到几百纳秒。访问硬盘驱动器可能需要数十毫秒秒。很多时候,I/O 会拖慢你的应用程序。
您的应用程序是执行少量大型 I/O 读取(在一个大块中读取 20MB 文件)还是无数小型读取(从一个文件读取字节 2,052 到 2073,然后从另一个文件读取几个字节)?更少的大型读取可以将您的 I/O 速度提高数千倍。
页面错误也涉及硬盘访问。内存中的页面必须被推送到页面文件,而分页的页面必须被读回内存。如果这种情况经常发生,它会很慢。您能否改善数据的局部性,从而减少同时需要的页面?您是否可以简单地为主机购买更多 RAM 以避免不得不分页数据? (作为一般规则,硬件很便宜。升级计算机是一个完全有效的优化 - 但要确保升级会有所作为。购买更快的计算机不会加快磁盘读取速度。如果一切都适合 RAM在您的旧系统上,购买内存是 8 倍的没有意义)
您的数据库也依赖于硬盘访问。那么,您可以在 RAM 中缓存更多数据,并且只是偶尔将其写入数据库吗? (当然有风险。如果应用程序崩溃了怎么办?
然后是每个人都喜欢的线程。现代 CPU 有 2 到 16 个 CPU 内核可用。你都在用吗?你会从使用它们中受益吗?是否有可以异步执行的长时间运行的操作?应用程序在单独的线程中启动操作,然后能够立即恢复正常操作,而不是阻塞直到操作完成。
所以基本上,使用分析器来了解您的应用程序。它如何花费它的执行时间,它在哪里花费?内存消耗有问题吗?什么是 I/O 模式(硬盘和网络访问,以及任何其他类型的 I/O)?
CPU 是一直在不停地运转,还是空闲等待一些外部事件,例如 I/O 或计时器?
然后尽可能多地了解运行它的计算机。了解它有哪些可用资源(CPU 缓存、多核),以及它们各自对性能的意义。
这一切都非常模糊,因为优化大型数据库服务器的技巧将非常不同于优化一些大型数字运算算法。