“现代OO语言如何几乎消除了进程中调用的开销”?

时间:2009-09-19 06:16:50

标签: oop language-design

我正在浏览Source Making网站,特别是Refactoring部分。在描述Long Method问题的页面上,出现以下声明:

  

旧语言带来了开销   子程序调用,这阻止了   来自小方法的人。现代OO   语言几乎被淘汰了   进程中调用的开销。

我只是想知道现代OO是如何做到这一点的,与“旧”方式相比如何呢?

7 个答案:

答案 0 :(得分:7)

不要相信你读过的一切


我认为你对这个声明的旅行是明智的。这毫无意义。

真的,我根本不相信这个说法。发生的事情是CPU的速度非常快,比设计那些旧语言快一千倍。

计划也变得更加复杂。在这一点上,我们不关心“分支和链接”中涉及的(现在)微小的开销或者函数调用机制。我们有数百万像素的绘画,或者要访问的数据库,或者要提供的网络。在某种程度上,这些操作很昂贵。方法调用在噪声中。

在C中进行方法调用的开销要比在任何现代语言中少得多。毕竟,现代语言首先有一个用C 编写的CLR或JVM或Ruby解释器。

但没关系。 CPU足够快,可以在下周启动程序。重要的是保持(主要是现在的OO)软件的层和层正常工作,现代语言帮助我们做到这一点,并使其更容易编写。

真的,它们更慢,而不是更快,因为这就是我们现在想要的方式。 3倍的开销,1000倍的CPU速度,我们仍然赢得300,并且拥有更好的语言。

答案 1 :(得分:2)

如果现有的编译器很短(而不是虚拟),它实际上会为你内联这个方法,这会带来一些性能提升。

除此之外,我认为特别是方法调用变得非常快。但另一方面,计算机有。在所有情况下(但可能是最极端的情况),关注可读性是一种更好的投资,而不是出于性能原因而制定长方法。

答案 2 :(得分:2)

看两句话:

  

旧语言在子程序调用中带来了开销,这阻止了人们使用小方法。   现代OO语言几乎消除了进程内调用的开销。

你想知道“老年人”和“现代”是什么意思,以及哪些语言特征可能影响表现。

如果它们意味着较旧的语言,例如Fortran,则它们完全错误 - 旧版本的Fortran不支持本地范围,因此子程序调用非常快,因为它们不需要保存局部变量所持有的值打电话的时候。为每个嵌套函数调用保存局部变量的要求构成了支持递归的C语言等开销。更高版本的Fortran添加了递归函数,但您必须将函数显式标记为递归。

所以基本上“老语言”的开销较小。无论是垃圾,还是他们将“现代OO语言”与“旧版 语言进行比较”

在传统的OO语言中,例如Smalltalk(Smalltalk是最古老的'纯'OO语言,但这也适用于最近的Smalltalk启发语言,例如Ruby和Python;就过程调用而言,Ruby非常传统) ,每个过程调用都可能是一个多态方法,因此就像在调用时在运行时通过名称查找一样。由于没有对语言进行任何更改,Smalltalk的现代实现通过内联重复调用的多态方法运行得更快。

但Smalltalk不是一种现代语言(在许多方面它是Lisp的方言,所以它的遗产是20世纪50年代,尽管它只是在20世纪70年代到来),并且改进了实现,而不是语言。 Sun Java运行时,Google JavaScript运行时和许多常见的lisp运行时都存在相同的改进; Java和JavaScript都是比Smalltalk更新的OO语言,但是方法调用优化仍然存在,尽管这些语言的功能(Java的静态类型会建议使用静态调度表,就像许多C ++实现一样,JavaScript的后期绑定和缺少类使得优化更难实现。)

我想不出一种方法来阅读这两个真实的句子。

如果你看一下文章的更广泛的上下文,就意味着代码的风格已经从长方法变为短方法。

是否它认为现在使用更新的OO语言(如Java或C ++ 0x)中的更短的方法编写此Smalltalk code from the 197Os

enter [ self show. edit Menu show. scrollbar show ]

leave [ document hideselection. editMenu hide. scrollbar hide ]

outside
  [editMenu startup => []
  scrollbar startup => [self showdoc]
  ^false]

pendown [ document pendown ]

keyboard [ document keyboard ]

这似乎也不太可能。 OO发生了变化,与Bee Gees一样现代化。

然而,在程序到OO代码之间,方法大小和重构方法发生了重大转变。

一旦你有了一个对象,其中的字段包含你正在使用它的数据就更容易将这一个对象传递给子程序而不是传递十几个不同的局部变量,这可能是小方法的最强原因在传统的OO中更常见,但它与性能和现代语言没有密切关系。这只是因为它有很多工作,并且很容易在C中的函数内部和之后纠缠12个double和int参数。

我一直处于查看一大块程序代码并创建一个对象(或C语言中的结构)来保持状态以允许它被重构,以及反向(处理大量字段)的情况进入局部变量并手动内联更短的方法)以提高性能(在Java 1.3 IIRC中)。由于您可以在ANSI C中进行重构,因此它几乎不受现代OO语言的限制。

答案 3 :(得分:1)

没有。还有一个开销。它相对于今天的架构而言非常小。如果您在486上运行代码,则会发出不同的曲调。

答案 4 :(得分:0)

除非您编写的硬件设备驱动程序必须非常快,否则设置堆栈帧和进行函数调用的开销通常与替代方案的成本相比微不足道。你试图调试的二十多页函数越多,短函数就越成为你的朋友。

答案 5 :(得分:0)

优化当然有所帮助,但这里有一个有意的权衡:在复杂性增加的情况下,花费更多的CPU周期来提高应用程序质量和可维护性。这是自第一个高级语言开发以来我们一直在做的权衡。

答案 6 :(得分:0)

我认为较新的整体系统可以从以下方面受益:

  1. 通过堆上的引用传递数据:有效地消除了在堆栈上复制大对象的需要。
  2. 垃圾收集:通过将程序员从管理对象生命周期的梦魇中拯救出来,使第一点在现实生活中变得有用。例如,从函数调用返回一个对象(实际上仅返回它的引用)将是非垃圾收集系统的噩梦。