90/10程序优化规则的含义是什么?


67

根据Wikipedia的介绍,程序优化的90/10规则指出:“程序执行时间的90%用于执行10%的代码”(请参见此处的第二段)。

我真的不明白。这到底是什么意思?如何仅在执行10%的代码上花费90%的执行时间?那么其余90%的代码呢?如何仅在10%的时间内执行它们?


50
代码的某些部分可能比其他部分执行得更多。毕竟,这就是循环的目的。在实践中,几乎总是有些部分被执行的方式往往比其他人。
凯莉安·佛斯

147
等到听到有关软件项目持续时间的90/10规则:“项目的90%将占用分配的时间的前90%;项目的最后10%将占用分配的时间的其余90%”。
Paul D. Waite

3
这里的困惑:“时间花在执行上”。考虑一下a++; for(i=0;i<100;i++){b++;} for(i=0;i<100;i++){print(xyz);}。当然,第一个for循环的花费比第一个语句多得多,但是第二个for循环的花费比第一个for循环多出约1000倍的时间,但是没有执行。它花费它等待打印。因此,花在执行上的时间与代码所负责的时间之间是有区别
Mike Dunlavey

32
@ Paul_D._Waite我以为是项目的90%花费了90%的时间,剩下的90%则花费了90%的时间,依此类推。在不到无限的时间内完成或完全调试。
nigel222 '16

9
对于实际示例,我研究过的几个代码(科学模型)使用了大量代码(约1万行)来读取和建立模型,然后循环执行几百行以进行实际计算。但是那个短循环是n ^ 4(在数千个时间步长中迭代了三个空间维度),因此花了几天的时间进行计算。因此实际比率可能更像是99%/ 1%:-)
jamesqf

Answers:


184

这里有两个基本原则:

  • 某些代码比其他代码执行得更多。 例如,某些错误处理代码可能永远不会使用。仅当您启动程序时才会执行某些代码。其他代码将在您的程序运行时一遍又一遍地执行。
  • 某些代码需要多少时间比其他代码运行。 例如,在数据库上运行查询或从Internet提取文件的一行可能要花费数百万次数学运算。

90/10规则实际上并不正确。它因程序而异(我怀疑90和10的具体数字是否有任何依据;有人可能凭空想出来了)。但关键是,如果您需要程序运行得更快,则可能只有很少的几行对实现这一目标很重要。确定软件的慢速部分通常是优化的最大部分。

这是一个重要的见解,它意味着对于新开发人员来说似乎违反直觉的决策通常是正确的。例如:

  • 许多代码都不值得花时间去做“更好的”,即使它以愚蠢的,简单的方式工作。您能为应用程序XYZ编写更有效的搜索算法吗?是的,但是即使有成千上万个值,实际上每个值的简单比较也需要很短的时间。因此,这是不值得的。对于新开发人员而言,避免不必要的优化可能很困难,因为在他们的学位课程中,花费了很多时间来编写“正确的”(意味着最有效的)算法。但是在现实世界中,正确的算法是能够运行且运行足够快的任何算法。
  • 使您的代码更长,更复杂的更改仍然可能会赢得性能。 例如,在应用程序FOO中,可能有必要添加数百行新逻辑,只是为了避免单个数据库调用。

6
特别要注意的是,使用排序功能之类的东西,在所有情况下,使愚蠢的简单算法做正确的事情要快得多(在开发时间内),而不是获得功能完善且没有错误的优雅算法。(在acadamea之外编写排序算法的唯一原因是,如果您正在构建图书馆或在没有图书馆的平台上工作……)
StarWeaver

5
我认为您需要将链接添加到shouldioptimize.com:)
Ivan Kolmychek

13
我认为90/10来自著名的80/20帕累托原理en.wikipedia.org/wiki/Pareto_principle
fernando.reyes

2
@StarWeaver这就是为什么像C ++这样重要的语言使编写高效的排序比起笨拙的冒泡排序更容易或更容易的原因。这样的“预打包”算法和代码可以真正得到最优化,而不会在使用时引起复杂性。
Yakk

6
@IvanKolmychek该网站具有误导性。当然,这种成本分析是要考虑的一个因素,但是还有其他因素,例如用户体验。您可能会因不进行优化而节省很多钱,但是如果人们对您的网站感到沮丧,您可能会错过很多收入。
jpmc26 2013年

21

这不是自然法则,而是经验丰富的经验法则。它也被称为80/20规则,只是一个大概的近似值。

循环,分支和其他流控制。

每个具有if的地方,您将拥有一个分支,该分支的使用频率高于另一个分支。因此,将更多的执行时间花费在执行程序的那部分而不是另一部分上。

每个地方都有一个循环运行不止一次,您执行的代码比周围的代码要执行的更多。因此,在那里花费更多的时间。

例如,请考虑:

def DoSomeWork():
    for i in range(1000000):
        DoWork(i)
    except WorkExeption:
        print("Oh No!")

在这里,print("Oh No!")遗嘱最多只能运行一次,并且通常永远不会运行,而DoWork(i)遗嘱大约发生一百万次。


7
称其为80/20规则可能会与帕累托原理混淆,帕累托原理不仅仅适用于编程。也许90和10只是方便的数字,其含义没有重叠。
trichoplax

29
这是帕累托校长的一个实例。两对数字都同样武断
Caleth

2
帕累托原理中的80/20拆分有数学基础。它们不仅仅是代表“很多”和“一点”的一些虚构人物。
Moyli

1
@Moyli-是的,“ 80/20分割有数学基础……”,但是在现实世界中,它永远不会(恰好是偶然,很少)恰好是80/20。
凯文·费根

2
@trichoplax的pareto原理在这里非常适用。20%的原因(代码行)导致80%的结果(运行时)
njzk2

16

循环。

我很想停在那里!:-)

考虑这个程序

1. do_something

2. loop 10 times
3.    do_another_thing

4.    loop 5 times
5.        do_more_stuff

第1行执行一次,而第3行执行10次。依次查看每一行

1 1   0.8%
2 10  8.3%
3 10  8.3%
4 50 41.3%
5 50 41.3%

两行占执行时间的83%(假设所有行都花费大约相同的时间来运行。因此40%的程序需要80%以上的时间。

在更多更实际的示例中,这种情况会增加,因此只有少量的行占了运行时间的大部分。

90/10规则(或有时使用80/20的规则)是“经验法则”-仅近似于真实。

另请参阅帕累托原理


2
与其说这仅是近似事实,不如说是在许多情况下,至少有 90%的时间将花在执行一小部分代码上(最多 10%)。显然,有可能所有程序都花费大约相同的时间来执行程序,但这很少见。
超级猫

+1用于引用帕累托原理。在这个很棒的Vsauce视频中可以看到更深入的解释。
Radu Murzea '16

5

当您仅询问执行时间时,此示例可能会有所帮助:

int main() {
    sleep(90); // approximately 10% of the program.
    // other 90% of the program:
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    return 0;
}

如果说得更认真一点,那就意味着在现实生活中的代码中,您几乎总是在循环中调用一个沉重的函数(而不是sleep(90);),而其余10%的时间执行一些单遍计算。

另一个示例是某些HA服务中的错误处理。任何高可用性服务都被设计为在正常情况下可以无限地工作。它通常在99%的时间中运行,但是有时在发生错误的情况下,它将运行一些错误处理和恢复,这在逻辑上可能比服务本身更为复杂。


很好,我希望有人发布这个极端的例子,以清楚地表明两者之间的区别。
djechlin '16

3

90/10推理意味着您的一小部分代码将比其他代码重复或使用更多。这通常用于建议您将90%的开发/优化工作集中在这10%的代码中。

考虑一个普通的文本处理器,例如Microsoft WordOpenOffice

  • 首选项对话框使用不多;
  • 绘制字符的子例程始终使用。

这句话在管理科学中也被使用...这是生活本身的教训...含义:将大部分精力集中在可以带来更多成果的地方。


6
如果Microsoft Word很简单,那么复杂的例子是什么?
Peter Mortensen

@PeterMortensen毫无道理。
大鸭

显然,@ PeterMortensen Emacs。
大师

2

想象这样一个程序:

print "H"
print "e"
print "l"
print "l"
print "o"
for i=0 to 1,000,000
    print "How long now?"
next
print "B"
print "y"
print "e"

注意这里有11行,其中11条中的3条是for循环,在这段相当小的代码上花了多少时间?相当多的时候,其他8行仅打印一个字符。因此,请注意,尽管某些代码可能很短,但这并不能告诉您它执行的频率和所需的时间。


0

正如其他出色答案所述,除了循环之外,还需要考虑DRY原则。写得好,面向对象的代码有很多可重用的部分。根据定义,那些被重用的部分的使用频率至少是一次执行的使用频率的两倍。如果您有很多OO代码,则可能会多次重用一些类和方法,而其他一些代码则只能重用一次。

如在其他答案中所提到的,花费更多的精力来使经常使用的代码比改善仅使用一次的代码更好。


2
您可以重用许多代码,但是所有代码很少执行(尽管仍然很关键)。
彼得·莫滕森

@PeterMortensen“关键但不经常”与“几乎每秒重用并且需要尽可能快地重载”不同
The Duck Duck

@TheGreatDuck,我认为那不是他的意思。因为您可以拥有不经常执行的代码,但是您希望它尽快发生。例如,让我们进行错误恢复-根据应用程序的不同,可能需要一些时间(5分钟,一个小时,甚至更多)来使系统重新运行。但是,例如,如果飞行系统遇到错误,则您确实希望尽可能快地将其启动。因为如果不这样做的话,它将在非常真实的意义上“崩溃”并“崩溃”。
VLAZ

这似乎暗示DRY需要OO,这当然是不正确的。重用同样通过游离功能等便利
underscore_d

@vlaz是对的,但实际上是在飞机上。...一切都需要快速运行。
大鸭

0

那不是一条规则,那只是一些花花公子,他编辑了Wikipedia,并凭空抽出了几个数字,称其为规则。与帕累托原则相比,后者在其他情况下更为牢固。我想看看对此“规则”的准确性进行了哪些研究(如果有)。

但基本上,您的问题的答案是,某些代码的执行频率比其他代码高得多。循环通常是造成这种情况的原因。其他原因是费时的呼叫,例如对外部资源(如Web服务或存储介质)的呼叫。


人们习惯使用这是合法的事情。
大鸭

如果您建议根据经验将其广泛使用,那么我也很乐意为此找到证据!还是只是另当别论而已,却暗含了事实?
布拉德·托马斯

如果您实际阅读了Wikipedia文章,您会发现asker所引用的引用具有以下引用:amazon.com/Every-Computer-Performance-Book-Computers/dp / ...我从来没有亲自看到过使用它,但是我认为您发布的内容粗鲁无礼,因此我回了。显然10%是一个人组成的数字。通过使程序效率低下,我可以将其设置为任意数量。但是,考虑到这里有多少人同意它的存在,因此是否在软件工程中使用该术语显然尚无定论。
大鸭

好吧,我不想去买这本书,只是为了看看它所谓的研究……您能从书中发表引用来证明证据吗?还是您实际上没有看到?
布拉德·托马斯

1
@BradThomas:反对90-10规则是由编辑Wikipedia的人发明的理论的证据是,它被广泛引用,数字90和10,比Wikipedia早很多年;真正的原理不是确切地10%的代码占运行时的90%,而是在大多数程序中,一小部分代码(占-10%或更少)占了运行时的大部分- -90%甚至更多,即使代码的这一小部分的性能提高甚至10%,也将减少总体执行时间,而其他所有方面的性能却提高1000倍以上。
超级猫

0

这是对“帕累托原则”的重新解释,该原则规定“对于许多事件,大约80%的影响来自20%的原因。”,也称为80/20规则。该规则主要适用于经济学,因此将其重新设计用于编程是有道理的。

这只是长期以来观察到的一种模式。

这是有关此类模式的非常不错的视频,它也解释了帕累托原理。

https://www.youtube.com/watch?v=fCn8zs912OE&ab_channel=Vsauce

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.