在为未知数进行设计时,如何避免进行优化的危险?
两个伙伴:
1)假设我们正在设计一种新型的应用程序,并且我们正在想出新的算法来表达概念和内容-在那个阶段尝试不积极考虑优化技术是否有意义?在脑海中,我们担心它最终可能会变成数百万个元素的O(N!)?
2)如果是这样,请说避免限制很酷的功能,一旦概念验证运行,我们就可以优化这些功能-如何使自己摆脱程序员一生的习惯?我一直在尝试脑力锻炼,纸笔记,但实际上我是从小在组装器中计算时钟周期的,因此我不断发现自己在充分考虑功能价值之前就过于浪费的潜在解决方案进行了否决。
编辑:这是关于设计以前从未做过的事情(未知),当我们甚至不确定是否可以在理论上完成时,不要介意拥有无限的计算能力。因此,"当然,在拥有原型之前,我们必须先进行优化,因为这是一种既定的计算原理"的答案并不是特别有用。
解决方案
我的大答案是测试驱动开发。通过预先编写所有测试,然后迫使自己仅编写足够的代码来实现所需的行为。如果需要定时和时钟周期,则可以编写测试以涵盖该情况,然后重构代码以满足这些要求。
"主动不考虑优化"听起来对我来说很奇怪。通常80/20规则效果很好。如果我们花费80%的时间针对不到20%的用例优化程序,那么最好不要浪费时间,除非那20%的用例确实很重要。
至于完美主义,除非它开始使我们放慢速度并使我们错过时间框架,否则它没有任何问题。计算机编程的艺术是在应用程序的美观与功能之间取得平衡的一种行为。为了帮助自己考虑学习时间管理。当我们了解如何分割和评估工作时,很容易决定是立即对其进行优化还是创建工作版本。
优化并不完全是危险;在编写代码时一定要考虑速度,这是一件好事,因为当一些更简单,更快速的事情发生时,它会阻止我们实施缓慢而混乱的解决方案。它还使我们可以确定是否可行。
可能发生的最糟糕的事情是,我们在设计大型程序时明确地忽略了优化,而回头却发现整个设计完全没有用,因为如果不完全重写就无法对其进行优化。如果我们在编写所有内容时都考虑到了这一点,那就永远不会发生,而"所有内容"的一部分就是潜在的性能问题。
"过早的优化是万恶之源"是万恶之源。我看到过一些项目由于过度使用此概念而瘫痪。在我公司,我们有一个软件程序,可以广播网络上磁盘上的传输流。它最初是为测试目的而创建的(因此我们一次只需要几个流),但它始终符合程序的规范要求,因此它可用于大量流,因此以后可用于点播视频。
因为它是完全忽略速度而写的,所以很混乱。尽管确实不需要,它仍然有大量的memcpys,其TS处理代码非常慢(实际上,每个TS数据包多次解析),依此类推。它一次只能处理40个流,而不是原来的数千个,而实际上是时候将其用于VOD了,我们不得不回去花费大量时间清理并重写大部分内容。它。
像安全性和可用性一样,从项目开始就必须考虑性能。因此,我们一定要在设计时考虑到良好的性能。
克努斯(Knuth)的老话是:"我们应该忘记效率低下,大约有97%的时间是这样:过早的优化是万恶之源。"从O(N!)到O(poly(N))并不是"小效率"!
处理类型1的最佳方法是从可能可行的最简单的事情开始(除非不扩展几个元素,否则O(N!)可能无法工作!)并将其封装在应用程序的其余部分中,因此我们可以将其重写为更好的方法,假设会出现性能问题。
如果我担心代码处理数据增长的能力,那么在我走得太远之前,我会尝试以大块增量设置样本数据集,以进行如下测试:
1000条记录
10000条记录
100000条记录
1000000条记录
并查看它在哪里破裂或者变得无法使用。然后,我们可以根据实际数据来决定是否需要优化或者重新设计核心算法。
我认为忘记算法的O(N!)最坏情况是很合理的。首先,我们需要确定一个给定的过程是完全可能的。请记住,摩尔定律仍然有效,因此即使是错误的算法也将在10或者20年内花费更少的时间!
首先优化设计-例如让它首先工作:-)然后优化性能。这是python程序员固有的折衷方案。通过使用通常在运行时速度较慢但级别较高(例如与C / C ++相比)并因此开发速度更快的语言进行编程,python程序员可以完成很多工作。然后,他们专注于优化。
一个告诫,如果完成所需的时间太长,以至于我们无法确定算法是否正确,那么这是一个很好的时机,我们可以担心上游的优化。我只遇到过几次这种情况-但很高兴知道这一点。
我会讲一个关于发生在我身上的事情的小故事,但并不是一个真正的答案。
我正在为一个客户开发一个项目,其中一部分正在处理服务器上的超大扫描(图像)。当我写它的时候,我在寻找功能,但是我想到了几种优化代码的方法,以便它更快并且使用更少的内存。
现在出现了一个问题。在向潜在客户进行此软件的演示和Beta测试期间,在演示单元(自带笔记本电脑)上,由于使用了过多的内存,因此失败。在具有很大文件的开发服务器上,它也会失败。
所以它是一个优化,还是一个已知的未来错误。我现在修复还是优化它?好吧,这是要确定的,因为它们也是其他优先事项。
这只是让我希望我确实花了一些时间在早些时候重新优化代码。
考虑一下操作方案。 ( 用例)
假设我们正在制作比萨店取景器小物件。
用户打开机器。它必须在有意义的时间内向他显示最近的披萨店。事实证明,我们的用户希望快速了解:不到15秒。
所以,现在,我们有任何想法,我们会认为:这将永远实现,实际上会在不到15秒的时间内运行,而将所有其他时间花在做重要事情上的时间都减少了。
或者我们是一个交易系统:准确的金额。如果可以的话,每笔交易少于一毫秒。 (他们可能会接受10毫秒),所以,阿吉安:我们从相关场景的角度来看每个想法。
假设这是一个电话应用程序:必须在下面启动(几秒钟)
总是向客户展示笔记本电脑的情况。我们必须出售产品。
维护,某些人升级事物总是一个场景。
因此,现在举个例子:所有困难的,AI繁重的,定制的方法都不适合。
或者对于不同的笔触,XML服务器配置文件不够用户友好。
看看有什么帮助。
我说所有以下这些不是因为我认为我们还不知道,而是在压制内心的批评家时提供道义上的支持:-)
关键是保持理智。
如果我们发现自己正在编写预期会扩展的Theta(N!)算法,那么我们就疯了。我们必须将其丢弃,所以我们不妨现在就开始寻找可以实际使用的更好的算法。
如果我们担心每位用户按键仅执行一次的Pentium代码是否需要10个周期或者10K个周期,那么我们就疯了。 CPU空闲95%。给它一万次的测量周期。如有必要,请筹集一张增强票,但要缓慢地离开汇编器。
决定该项目是"编写研究原型,然后将其演变为真实产品"还是"编写研究原型"。显然期望如果研究成功,将会有另一个相关的项目。
在后一种情况下(从注释中听起来像我们所拥有的),我们可以负担得起只能在N <= 7的情况下编写的内容,甚至会导致从此处到辛辛那提的电源不足。那仍然是我们不确定自己可以做的事情。一旦感觉到问题,我们将对性能问题有一个更好的了解。
我们正在做的事情是在现在浪费时间(考虑到研究证明是无关紧要的)和以后浪费时间(因为我们现在没有考虑某些事情变得很重要)之间取得平衡。研究风险越大,我们做某事就应该越高兴,并担心以后做些什么。
根据一个人的回答,在优化代码和优化算法之间存在很大的差异。
是的,在此阶段,优化代码将带来可疑的好处。我们不知道真正的瓶颈在哪里,也不知道首先是否会出现速度问题。
但是即使在算法/数据结构等开发阶段,也要注意扩展问题,这不仅合理,而且我认为必不可少。毕竟,如果后壳分析表明我们将无法在宇宙的热死事件发生之前就运行完闪亮的新应用程序,那么就没有多大意义了。 ;-)
"首先,使其运行。然后使其快速运行。"
或者
"要先完成,首先必须要完成。"
慢速存在的应用程序通常比超快速不存在的应用程序好。
首先,人们宣称,终点是唯一重要的事情(或者几乎)。
但是,如果我们完成其主要算法具有O(N!)复杂性的产品,则根据经验,我们没有完成它!我们有99%的情况不完整且不可接受的产品。
合理的性能是工作产品的一部分。完美的性能可能不是。如果我们完成了一个需要6 GB内存来编写简短便笺的文本编辑器,那么我们根本没有完成产品,那么时间就浪费了。使产品完整的功能,使其能够满足客户/用户的需求。如果失败了,那么按计划完成代码编写就无关紧要。
因此,所有避免产生无用产品的优化都应在不影响其余设计和实现过程的前提下予以考虑和应用。
我喜欢这个问题,因此即使别人已经回答了,我也要给出答案。
当我在麻省理工学院AI实验室读研究生时,我们一直都在面对这种情况,我们试图编写程序来获得对语言,视觉,学习,推理等方面的理解。
我的印象是,那些有进步的人对编写有趣的程序而不是快速的程序更感兴趣。实际上,花在担心性能上的时间基本上是从花在构思有趣行为上的时间中减去的。
现在,我从事更多平淡无奇的工作,但同样的原则也适用。如果我能正常工作,那么我总是可以使其更快地工作。
但是我要提醒的是,现在教授软件工程的方法强烈鼓励从积雪中走出困境。不仅要完成任务,还需要教人们创建一个类层次结构,该层次结构具有尽可能多的抽象层,包括服务,接口规范,插件以及阳光下的所有内容。他们没有被教导尽可能少地使用这些东西。
结果是软件过于复杂,难以优化,因为更改起来更加复杂。
我认为避免这种情况的唯一方法是获得大量的性能调整经验,并以此来识别导致这种过度复杂化的设计方法。 (例如:过分强调类和数据结构。)
这是一个调整应用程序的示例,该应用程序已按照一般的讲授方式编写。