我想问一下在Visual Studio规模方面具有丰富经验的人:是什么让它们变慢了?是将代码库保持在人类理解能力范围内所需的抽象层吗?是否需要运行大量的代码?在时钟周期/内存使用部门(付出惊人的巨大代价)上,是否倾向于节省程序员时间的方法的现代趋势?
我想您猜到了很多,但是我想提供我认为是最大的因素,因为在相当大的代码库上工作(不确定它是否与Visual Studio一样大-包含数百万行代码)类别和大约一千个插件)约10年的时间,并且会出现观察现象。
由于它没有涉及API或语言功能或类似功能,因此它的争议也较小。这些与“成本”有关,它可能引发辩论而不是“支出”,我想集中讨论“支出”。
松散的协调和传统
我观察到的是,松散的协调和长期的遗留往往会导致大量累积的浪费。
例如,我在此代码库中发现了大约一百种加速结构,其中许多都是冗余的。
我们想要一棵用于加速一个物理引擎的KD树,一棵用于经常与旧物理引擎并行运行的新物理引擎的KD树,我们将有数十种用于各种网格算法的八叉树实现,另一棵用于渲染的KD树,采摘等等等。这些都是大而笨重的树形结构,用于加速搜索。对于一个非常平均大小的输入,每个人可能要占用数百兆到千兆字节的内存。它们并不总是被实例化并一直使用,但是在任何给定时间,它们中的4或5可能同时在内存中。
现在,所有这些都存储了完全相同的数据,以加快对它们的搜索。您可以像模拟旧数据库一样想象它,该数据库将其所有字段一次存储到20个不同的冗余映射/字典/ B +树中,并通过相同的键进行相同的组织,并始终对其进行搜索。现在,我们要处理20倍的内存和处理。
此外,由于存在冗余,因此几乎没有时间用随之而来的维护价格标签来优化其中的任何一个,即使我们这样做了,也只能达到理想效果的5%。
是什么原因导致这种现象?松散的协调是我看到的第一大原因。许多团队成员经常在各自孤立的生态系统中工作,开发或使用第三方数据结构,但是却没有使用其他团队成员所使用的相同结构,即使他们完全是完全相同的关注点。
是什么导致这种现象持续存在?传统和兼容性是我看到的第一大原因。由于我们已经支付了实现这些数据结构的成本,并且大量代码依赖于这些解决方案,因此尝试将它们合并为更少的数据结构通常太冒险了。即使这些数据结构中的许多在概念上都是高度冗余的,但在接口设计中它们并不总是接近相同。因此,与仅让它们消耗内存和处理时间相反,替换它们将是一个巨大且冒险的更改。
记忆效率
通常,内存使用和速度往往至少在批量级别上相关。您通常可以通过占用内存的方式来发现速度较慢的软件。并非总是如此,因为更多的内存会导致速度下降,因为重要的是“热”内存(一直在访问什么内存-如果程序使用大量的内存,而所有程序仅使用1 MB的内存),时间,那么在速度上就没什么大不了的)。
因此,您可以经常根据内存使用量发现潜在的猪。如果应用程序在启动时占用数十至数百兆的内存,则可能效率不高。如今,当我们拥有千兆字节的DRAM时,数十兆字节可能看起来很小,但是最大和最慢的CPU高速缓存仍在可怜的兆字节范围内,而最快的仍然在千字节范围内。结果,从硬件CPU缓存的角度来看,仅使用20兆字节启动且不执行任何操作的程序实际上仍在使用“大量”内存,特别是如果该内存的全部20兆字节将被重复访问并程序运行时频繁运行。
解
对我来说,解决方案是寻找更协调,规模更小的团队来构建产品,他们可以跟踪自己的“支出”并避免一遍又一遍地“购买”相同的商品。
成本
我将深入讨论更具争议性的“成本”方面,只是我观察到了一些带有“支出”现象的现象。如果一种语言最终给对象带来了不可避免的价格标签(例如提供运行时反射并且无法强制为一系列对象进行连续分配的价格标签),则该价格标签仅在非常细粒度的元素(例如单身Pixel
或Boolean
。
然而,我看到了很多的源代码里面做处理重负载(例如:处理几十万到上百万的程序Pixel
或Boolean
实例)在这样的粒度级别支付该费用。
面向对象的编程会加剧这种情况。然而,这并不是“对象”本身或什至是错误的OOP的代价,只是这样的费用是以微小的微小元素支付的,将被数百万例示。
这就是我正在观察的其他“成本”和“支出”现象。成本是几美分,但是如果我们要单独购买一百万罐苏打水,而不是与制造商进行批量购买,则要花费几分钱。
对我来说,解决方案是“批量”购买。即使在每种语言都带有几美分的价格的语言中,对象也可以很好地实现,前提是该成本不会比类似的汽水罐高出一百万倍。
过早优化
我从来不喜欢这里使用的Knuth措词,因为“过早的优化”很少会使现实的生产程序运行得更快。有人将其解释为“尽早优化”,而Knuth的含义更像是“没有适当的知识/经验来进行优化以了解其对软件的真正影响”。如果有的话,真正的过早优化的实际效果通常会使软件变慢,因为可维护性的降低意味着几乎没有时间优化真正重要的关键路径。
这是我观察到的最后一种现象,开发人员在购买一罐苏打水时节省了几分钱,再也买不到,或更糟的是,房子浪费了所有的时间捏着几分钱(或更糟的是,想象中的几分钱从无法理解他们的编译器或硬件体系结构),而在其他地方浪费了数十亿美元。
时间是非常有限的,因此在没有适当的上下文信息的情况下尝试优化绝对值通常会使我们失去优化真正重要位置的机会,因此,从实际效果上来说,我会说“过早的优化会使软件运行缓慢。 ”
问题在于,有一些开发人员类型会采用我在上面写的有关对象的内容,并尝试建立一种编码标准,以禁止面向对象的编程或类似的疯狂方式。有效的优化是有效的优先级划分,如果我们陷入了维护难题的海洋中,那绝对是毫无价值的。