【问题标题】:Should software be designed with performance in mind?软件的设计应该考虑性能吗?
【发布时间】:2009-10-10 13:59:40
【问题描述】:

在设计软件的组件或架构时考虑性能是否可取?我的意思是,设计/架构应该准备好在性能密集型环境中使用吗?

在设计组件时,我们是否应该遵循良好的 OO 原则并确保组件是“可扩展的”。这样,当我们遇到性能问题时,我们会在这里和那里稍微调整设计。尽管这样,我们经常会遇到性能问题,稍微调整软件可能无济于事。

或者,如果我们想出一个设计,虽然很复杂,但性能问题却轻而易举。我们仍然需要调整软件,但调整通常非常简单,因为设计是面向性能的。

注意:在上述两种情况下,我都没有尝试在遇到性能问题之前调整软件的性能。换个说法,软件的设计是否应该以性能为导向?

请不要回答我说这完全取决于软件预期运行的环境。原因是任何工业级软件的客户似乎总是想要越来越多。您可能不会计划您的软件在性能密集型环境中持续运行,但如果必须这样做呢?当我们感觉到这一点时,我们是否应该重新设计软件?

这个问题困扰了我一周,我还没有答案。您对此有何看法?

【问题讨论】:

  • 对不起,但“这取决于”是唯一正确的答案。通常,您必须在可维护性和性能之间做出平衡。
  • 重新标记 - 从“java”更改为“language-agnostic”,“oops”更改为“oop”;添加了“最佳实践”。希望这会给更广泛的观众。如果 OP 选择将它们改回来,我不会重新编辑它们。

标签: language-agnostic oop design-principles


【解决方案1】:

当我写这篇文章时,已经有两个人回复了 Knuth 关于过早优化的引用。我认为这有点误导。在我看来,这背后的想法以及关于这个主题的许多建议背后的想法是,程序是算法的集合,如果它不够高效,我们可以确定哪个算法太慢并用某种东西替换它更好。

这种东西忽略了程序的互联性。这些算法都隐藏在一些 API 后面。虽然“愿景”是 API 背后的算法是不透明的并且可以与另一个算法互换,但它忽略了 API 对其调用者施加的约束。我已经完成了相当一部分网络编程,并且通过设计根本无法有效工作的 API 很容易编写低效的软件,那么当您必须对一个正在使用的 API 进行根本性更改时,您会怎么做? (在网络编程中,需要调用者在内存中构建完整消息的 API 比允许流式传输数据的 API 更容易设计和实现。)

所以,不要听信简单而精辟的引语。你不应该为小事操心(尤其是根本不用担心 70 年代的人所做的事情;编译器现在更聪明了),而是完全无视性能问题,态度是“我们总是可以稍后分析和改进事情”如果需要”可能会导致您进入死胡同,您必须进行大量的重新实现。

哦,我还建议不要“为可扩展性而设计”。做最简单的事情,如果你后来发现你所拥有的东西的概括使事情变得更容易或更简单,那就去做吧。以我的经验,进行不必要的通用设计只会导致更难使用的组件通常不是非常可扩展,因为最初的设计实际上无法预见组件在一般情况下应该做什么以及如何。

【讨论】:

  • 此外,Knuth 的引用主要适用于实施中的激进优化和捷径。根据您的要求的性能特征选择适当的算法和数据结构是完全合适的,尤其是在考虑渐近性能时。否则我们很少使用哈希表,总是选择关联列表。它们很简单,而不是过早的优化!
  • 如果性能很重要,则必须将性能列为一项要求。当然,要成为一项要求,它还必须满足具体的标准,例如,“必须能够处理在目标环境中运行的 10k 事件/秒”,其中“目标环境”也被精确定义。如果你有这个,那么当然任何设计都必须适应性能。值得注意的是,Knuth 关于过早优化的引用也可以应用泛化:不要过早泛化。
【解决方案2】:

项目的设计必须平​​衡可扩展性、可维护性、性能、交付时间等等。

我尝试设计包+高级图以实现可扩展性,然后设计低级图以提高性能。

【讨论】:

    【解决方案3】:

    我必须全心全意地回答 jk 的答案。

    Knuth 的话在现实生活中有些不适用,除了一些不涉及架构的小问题

    例如,我最近不得不花费 3-4 个月的时间从头开始重新构建一个相当复杂的系统,因为最初的设计假设 100% 的数据将从数据库的一个块中加载。这在 3 年内都很好,直到数据集增长到原始设计者预期的约 100 倍,并且系统开始在 2G 使用时内存不足或严重崩溃之间交替出现。

    现在,解决方案在概念上很简单 - 允许从数据库中批量检索数据。 这样做很聪明。但是,如果他们费心去考虑性能变成了 3 个月的磨难,那么在最初的设计阶段可能需要额外几周的工作,因为每个小功能、对象和 API 以及整体架构都被明确编写为假设“100%数据在那里”。

    一般来说,在数据量是性能问题并且数据分块是主要可行解决方案的任何情况下,必须为预先设计分块

    【讨论】:

      【解决方案4】:

      只要您从一开始就不知道每一点性能都很重要,我会说要遵循良好的面向对象原则。

      通常通过算法优化而不是架构重构来获得巨大的性能提升(只要架构遵循正常的最佳实践)。选择更难使用的设计所获得的性能提升通常在性能要求最高的环境中是无关紧要的,因此如果从一开始就不需要绝对的顶级性能,请选择良好的 OO。

      【讨论】:

        【解决方案5】:

        我想说,这就是经验丰富的软件工程师和软件新手的不同之处。

        经验丰富的软件工程师应时刻牢记其设计的性能问题。

        示例:当您的模块内部有一个算法具有 O(n^3) 性能行为并且 n 可能增加时,可能会出现这种情况,即您的模块在某些情况下会变得非常慢。

        当然,有很多不同之处。当您在内存阵列上使用 O(n^3) 时,在磁盘操作上使用 O(n^2) 时问题可能会更小。

        因此,经验对于思考这些事情并决定必须更改设计的地方或以后的调整可以使其更快而没有问题的地方很重要。

        【讨论】:

          【解决方案6】:

          遵循 OOP 最佳实践、广泛使用设计模式的架构良好的软件是或原则上应该是可维护性良好的软件。现在很少有低级优化真正发挥作用,CPU和资源相当过剩。

          只是代码可重用、可维护和可扩展。进一步低级优化的实际需求将在这样一个良好的环境中轻松实现。只有在真正需要的时候,只有在真正需要处理这个问题的时候。

          【讨论】:

            【解决方案7】:

            您应该始终以效率而非低效率为目标,而不是以可维护性为代价。所以是的,你应该尝试设计效率,但要警惕过早的优化。 Donald Knuth 最喜欢的一句话:

            “我们应该忘记小的效率,比如大约 97% 的时间:过早的优化是万恶之源。”

            【讨论】:

            • 我以为金钱是万恶之源?
            • 您是否试图证明过早优化 == 金钱?
            【解决方案8】:

            几乎以“视情况而定”的方式,我认为您确实需要考虑您的要求。如果最高优先级的要求之一是“必须能够维持某种疯狂的吞吐量/性能水平”,那么在整体架构和技术选择中不预先计划和设计就太疯狂了。

            【讨论】:

              【解决方案9】:

              我觉得有趣的是只有 Mikael Auno 提到了“要求”这个词。

              虽然 Knuth 的报价是 TRVTH,但这一切都归结为要求。可扩展性是其中之一吗?预期负载是多少?如果您的回答是“我不知道”,问。

              如果这些是要求,请将负载测试添加到您的验收测试中。

              您仍然希望进行可维护性设计。将性能考虑推迟到 Last Responsible Moment,然后是配置文件 - 不要猜测。微优化是浪费公司的钱。

              有时,负责任的时刻发生得相当早;我不会设计一个所有数据都作为 XML 文件存储在磁盘上的企业 CRM 系统。我要做的是抽象持久层。

              最后,Kolibri 的评论是正确的 - 答案(和往常一样)是“视情况而定”。

              编辑:在重新阅读时,恐怕我违反了 OP 的“请不要回答我说这完全取决于软件预期运行的环境”的约束。不过,我坚持我的回答。如果(当)需求发生变化,简单的设计通常更容易修改。未说明的假设是我们提前知道如何需求将发生变化。请求可能是“使其按数量级扩展”或“允许在组织之间移动客户”。为前者进行架构可能会使后者更难以实施。

              【讨论】:

                【解决方案10】:

                不要提前做任何优化。但是架构对系统的潜在性能有巨大的影响。

                我建议对以下书籍进行评分:Release It!: Design and Deploy Production-Ready Software

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2010-09-23
                  • 2011-06-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-08-23
                  相关资源
                  最近更新 更多