《编程匠艺》读书笔记之九

第十一章 追求速度
  • 优化是一个悬浮在软件开发上的幽灵,很多编程错误都是以效率的名义犯下的。
  • “优化”指改善某个事物以使它更好,对于更好,从不同方面看,有不同的理解:1. 使程序运行速度更快;2. 减少可执行文件的大小;3. 提高代码的质量;4. 提高计算结果的准确性;5. 将启动时间减到最小;6. 增加数据的吞吐量;7. 减少存储开销。
  • 对于优化,建议如下:不要做优化。
  • 一种错误的想法:只有在开发结束使你的代码运行的不够快的情况下,再考虑是否进行优化。
  • 代码的性能由许多因素决定,包括:1. 程序执行的平台;2. 部署和安装的配置;3. 体系结构软件方面的决策;4. 低级的模块设计;5. 遗留的历史问题;6. 每行源代码的质量。
  • 要从一开始就要考虑你的程序的性能,而不是置之不理。
  • 正确的代码远远比速度快的代码重要,快速得到错误的结果是毫无意义的。所以我们应该花更多的精力去证明代码运行是正确的。

    性能问题的产生可能基于以下几个原因:
  • 复杂性。不必要的复杂性是一个杀手,需要做的工作越多,代码就会运行的越慢。
  • 间接。所有的问题都可以由一个额外的间接层来解决。但是间接也产生了大量的抽象。
  • 重复。
  • 糟糕的设计。糟糕的设计必然导致糟糕的代码,它可能是导致最基本的、最细微的和最难解决的性能问题。
  • I/O。一个总是等待输入或输出的程序,其性能注定会非常糟糕。

    为什么不进行优化呢,因为优化代码是将一种良好的特性与另一种相交换的行为,代码的某些方面将受到伤害,表现在以下几个方面:
  • 可读性的损失。大部分“优化”的代码都非常凌乱,非常难懂。
  • 复杂性的增加。复杂性是优秀代码的敌人。
  • 难以维护/扩展。优化之所以会妨碍代码的可扩展性,是因为它常常来源于进行更多的设想。
  • 引入了冲突。优化往往是基于某个平台,为一种处理器选择最优的数据类型,可能会导致其他处理器上较慢的运行速度。
  • 更多的努力。我们需要关注优化工作的优先级。

  • 寻找对代码进行优化的替代方案,你能以任何其他方式提高你的程序的性能吗?尽可能不要通过修改代码的方式进行优化。
  • 我们在做软件项目时,需求文档中很少会对性能作出规定,但是如果你的程序运行的太慢,用户就会抱怨。
  • 理解你何时才确实需要对代码进行优化,最好是从一开始就编写高效和高质量的代码。

    我们是程序的运行速度加快,可以分为以下几个步骤:
  • 确定程序运行的太慢,并证明你的确需要进行优化。
  • 找出运行的最慢的代码,以这段代码为目标。
  • 测试这段作为优化目标的代码的性能。
  • 对这段代码进行优化。
  • 测试优化后的代码是否仍然可以正常运行(非常重要)。
  • 测试速度增加了多少,并决定下一步做什么。

  • 在开始优化时,有一个清晰的目标非常重要。
  • 为了正确的进行优化,你必须很小心,以防止外部因素改变你的代码的运行方式。
  • 单独优化你的代码,与所有其他工作都分开,这样一项任务的结果就不会影响其他任务。
  • 我们应该忽略较小的效率,在97%的时间里我们都能说,不成熟的优化是万恶之源。
  • 80/20原则在程序中的运用:平均来看程序超过80%的运行时间会花在少于20%的代码上。

    查找程序中影响性能的代码段,可以采取以下的方法:
  • 在代码中随处放置一些手动的计时器进行测试。
  • 计算每个函数的调用频率。
  • 利用编译器提供的钩子,在进入和退出每个函数的地方插入你自己的计数代码。
  • 对程序计数器进行取样。
  • 通过让单个函数变慢来测试它对整个程序执行时间的影响。

  • 尝试分析几个不同的数据集,观察结果有什么不同,选择一个非常基本的数据集、一个高负荷的数据集和一些普通的数据集。
  • 性能不足的原因也许不是某个具体的函数,而是一个涉及面更大的设计上的缺陷。不要只依赖于分析器来查找程序效率低下的原因,你也许会错过重要的问题。
  • 你必须在对代码修改之前和修改之后都要对性能进行测试,以确保你的修改确实使代码不同,并却确保修改确实使代码变更更好。永远不要在没有执行前后性能评估的情况下尝试对代码进行优化。
  • 不要忘记对优化后的代码进行评测,以证明你所做的是一个成功的修改。
  • 清晰的代码要好过有限的优化。
  • 常用的优化技术包括:设计更改和代码更改。与几行糟糕的源代码相比,抵消的设计更能束缚程序的效率。
  • 大多数情况下我们的优化目标是提高代码的运行速度,优化策略是:1. 加快较慢代码的速度;2. 尽量少做较慢的事情;3. 将较慢的事情推迟到不得不进行的时候再做。
  • 设计更改是宏观层面上的优化,即在较大的范围内进行修改,以改善软件的内部设计。
  • 在对程序中使用的算法进行优化时,最好使用较快的算法来代替较慢的算法,而不要胡乱的修补算法的具体实现。

    代码更改时,通常要打开编译器优化功能,或增加优化水平,常用的方法包括:
  • 循环展开。对于主题非常短的循环,循环的框架也许比循环执行的操作本身还要耗费资源。
  • 代码内嵌。通过合并调用方和被调用方来移除对函数的调用,可以提高代码的性能。
  • 常量叠算。可以在编译时进行涉及常量值的运算,以减少运行时的工作量。
  • 移到编译时,许多条件测试可以静态的加以验证,并从代码中移除,有些测试可以完全被避免。
  • 强度折减。指用一个等价但是执行速度更快的操作来代替某个操作,通常都是位运算。
  • 子表达式。
  • 无用代码删除。

  • 我们需要在设计时就进行性能方面的考虑,在设计每个模块时,不要盲目的追求性能,如果你知道需要什么样的性能水平,那么为适当的效率而设计就会更容易一些。
  • 在优化时,要非常系统,并权衡各种因素,要有一个清晰的目标,并证明每个步骤都使你更加接近目标。让可靠的代码而不是你的直觉来引导你。

  • 优秀的程序员:1. 避免进行优化,除非证明绝对需要;2. 系统的进行优化,采用深思熟虑和经过权衡的方法;3. 在求助于代码级优化之前,积极地寻找替代方案,并尝试设计级的改进;4. 更喜欢不会破坏代码质量的优化。
  • 糟糕的程序员:1. 在证明代码速度不够之前就开始进行优化;2. 非常轻率,不进行权衡或研究就改动哪些他们认为是瓶颈的代码;3. 从不从宏观地角度考虑:他们的优化在其他代码区域和使用模式中意味着什么;4. 认为速度比代码的质量更重要。
posted @ 2008-11-02 20:58  李潘  阅读(519)  评论(0编辑  收藏  举报