20.3 围绕关键路径进行设计
此时,我们假设你已经仔细地分析了性能,并且已经确定了一段慢到足以影响整个系统性能的代码。提高其性能的最好方法是进行“根本性”的变更,例如引入缓存,或者使用不同的算法方法(例如平衡树与列表)。我们决定在RAMCloud中绕过内核进行网络通信,就是一个根本性修复的例子。如果你能确定一个根本的修复方法,那么你就可以使用前几章中讨论的设计技术来实现它。
不幸的是,有时会出现没有根本性修复的情况。这就把我们带到了本章的核心问题,也就是如何重新设计一段现有的代码,使其运行得更快。这应该是你最后的手段,而且不应该经常发生,但在有些情况下,它可以带来很大的变化。关键的想法是围绕关键路径设计代码。
首先问自己在常见情况下执行所需任务必须执行的最少代码量是多少。不考虑任何现有的代码结构。想象一下,你正在写一个新的方法,只实现关键路径,即最常见的情况下必须执行的最少代码量。当前的代码可能充满了特殊情况;在本练习中忽略它们。当前的代码可能会在关键路径上遇上好几个方法的调用;相反,设想你可以把所有相关的代码放在一个方法中。当前的代码还可能使用各种变量和数据结构;只考虑关键路径所需的数据,并假设任何对关键路径最方便的数据结构。例如,将多个变量合并为一个单一的值可能是有意义的。假设你可以完全重新设计系统,以尽量减少关键路径必须执行的代码。让我们把这段代码称为“理想”。
理想的代码可能与你现有的类结构相冲突,也可能不实用,但它提供了一个很好的目标:这代表了这段代码最简洁最快速的样子。下一步是寻找一个新的设计,尽可能地接近理想,同时仍有一个干净的结构。你可以应用本书前几章的所有设计思想,但要有一个额外的约束条件,即保持“理想”代码(大部分)的完整。你可能需要在“理想”中增加一些额外的代码,以便实现简洁的抽象;例如,如果代码涉及哈希表的查找,则可以额外引入对通用哈希表类的方法调用。根据我的经验,几乎总是可以找到一个干净、简单而又非常接近于理想的设计。
在这个过程中,最重要的事情之一就是将特殊情况从关键路径中移除。当代码很慢时,往往是因为它必须处理各种情况,而代码被结构化以简化对所有不同情况的处理。每种特殊情况都会在关键路径上增加一点代码,其形式是额外的条件语句和/或方法调用。这些增加的代码都会使程序变得更慢。当为提高性能而重新设计时,尽量减少你必须检查的特殊情况的数量。理想情况下,在开始的时候会有一个单一的if
语句,通过一个测试来检测所有的特殊情况。在正常情况下,只需要做这一个测试,之后就可以执行关键路径,不需要再对特殊情况进行测试。如果最初的测试失败(这意味着发生了特殊情况),代码可以分支到关键路径之外的一个单独的地方来处理它。对于特殊情况,性能并不那么重要,因此你可以为了简单而不是性能来构建特殊情况代码。
Last updated