14

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

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

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

注意:在上面列出的任何一种情况下,我都没有尝试在遇到性能问题之前调整软件的性能。重新表述这个问题,软件的设计是否应该以性能为导向?

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

这个问题一直困扰着我一个星期,我还没有答案。你对此有什么看法?

4

10 回答 10

27

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

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

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

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

于 2009-10-10T14:25:20.347 回答
6

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

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

于 2009-10-10T14:04:35.317 回答
3

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

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

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

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

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

于 2009-10-10T15:02:05.343 回答
2

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

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

于 2009-10-10T14:12:19.903 回答
2

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

一个有经验的软件工程师应该时刻牢记他的设计的性能问题。

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

当然,有很多不同之处。当您在内存阵列上有 O(n^3) 时,它可能不像磁盘操作上的 O(n^2) 那样成问题。

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

于 2009-10-10T14:17:55.527 回答
1

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

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

于 2009-10-10T14:08:44.810 回答
0

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

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

于 2009-10-10T14:04:09.797 回答
0

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

我建议对以下书籍进行评分:发布它!:设计和部署生产就绪软件

于 2009-10-11T10:00:55.877 回答
0

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

于 2009-10-10T15:31:49.417 回答
0

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

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

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

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

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

最后,Kolibri 的评论是正确的——答案(像往常一样)是“取决于情况”。

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

于 2009-10-10T15:31:59.183 回答