zoukankan      html  css  js  c++  java
  • 《编程匠艺》读书笔记之九

    第十一章 追求速度
    • 优化是一个悬浮在软件开发上的幽灵,很多编程错误都是以效率的名义犯下的。
    • “优化”指改善某个事物以使它更好,对于更好,从不同方面看,有不同的理解: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. 认为速度比代码的质量更重要。
  • 相关阅读:
    反向迭代
    c++知识点
    LeetCode-Count Bits
    LeetCode-Perfect Rectangle
    LeetCode-Perfect Squares
    LeetCode-Lexicographical Numbers
    LeetCode-Find Median from Data Stream
    LeetCode-Maximal Square
    LeetCode-Number of Digit One
    LeetCode-Combination Sum IV
  • 原文地址:https://www.cnblogs.com/wing011203/p/1325016.html
Copyright © 2011-2022 走看看