Python(和其他动态语言)的哪些语义特征导致其缓慢?


26

我不太了解Python。我试图更精确地了解动态语言(如Python,Lua,Scheme,Perl,Ruby等)的确切功能正迫使他们的实现变慢。

作为一个例子,Lua 5.3的可继承机制会直观地使Lua变得很慢,但实际上有传言说Lua相当快(并且比Python快)。

另外,我有直觉(可能是错误的),由于目前的处理器内存大于原始计算慢得多(与高速缓存未命中的存储器访问需要的同时,数以百计的算术运算),动态类型检查(点菜if (value->type != INTEGER_TAG) return;的C语言)可以运行得很快。

当然,随着翻译程序的快速运行,整个程序分析(例如Stalin Scheme实现的工作)可以使动态语言实现成为可能,但是让我们假设我没有时间先设计整个程序分析器。

(我在MELT监视器中设计了一种动态语言,其中有些会翻译成C语言)



1
Lua Performance Tips,它解释了为什么某些Lua程序运行缓慢,以及如何解决它们。
罗伯特·哈维

Answers:


24

Python(和其他动态语言)的哪些语义特征导致其缓慢?

没有。

语言实现的性能是金钱,资源和博士学位论文的功能,而不是语言功能。Self比Smalltalk更具动态性,比Python,Ruby,ECMAScript或Lua更具动态性,并且它的VM优于所有现有的Lisp和Smalltalk VM(实际上,Self发行版附带了一个用Self编写的小型Smalltalk解释器,甚至比大多数现有的Smalltalk VM还要快),并且与当时的C ++实现竞争,有时甚至更快。

然后,Sun停止了对Self的资助,IBM,微软,英特尔和Co.开始对C ++进行资助,这种趋势反过来了。Self开发人员离开Sun创立了自己的公司,在那里他们使用为Self VM开发的技术来构建有史以来最快的Smalltalk VM(Animorphic VM),然后Sun购回了该公司,并对其进行了稍微修改。 Smalltalk VM现在以“ HotSpot JVM”的名称而闻名。具有讽刺意味的是,Java程序员视动态语言为“慢”,而事实上,Java在采用动态语言技术之前一直很慢。(是的,没错:HotSpot JVM本质上是Smalltalk VM。字节码验证程序会进行很多类型检查,但是一旦字节码被验证程序接受,VM尤其是优化程序和JIT实际上就不会做对静态类型非常感兴趣!)

CPython并没有做很多使动态语言(或动态调度)快速化的工作:动态编译(JIT),动态优化,投机内联,自适应优化,动态反优化,动态类型反馈/推断。还有一个问题,就是几乎所有的核心和标准库都是用C编写的,这意味着即使您突然将Python的速度提高了100倍,也无济于事,因为大约95%的代码由A执行Python程序是C,而不是Python。如果所有内容都是用Python编写的,那么即使是适度的加速也会产生雪崩效应,算法会变得更快,核心数据结构也会变得更快,但是当然,核心数据结构也将在算法中使用,核心算法和核心数据也将被使用。结构用于其他地方,

在当今的系统中,有几件事对内存管理的OO语言(无论动态还是非动态)都是不利的。虚拟内存和内存保护可以成为特别是垃圾回收性能以及整个系统性能的杀手。而且,使用内存安全的语言完全没有必要:为什么在没有使用该语言的任何内存访问的情况下,防止非法的内存访问?Azul已经发现可以使用现代功能强大的MMU(Intel Nehalem和更新的版本,以及与AMD相当的MMU)来帮助进行垃圾回收,而不是阻碍垃圾回收,但是即使CPU支持它,主流操作系统的当前内存子系统也不够强大。允许这个(这就是为什么Azul的JVM实际运行在裸金属虚拟化之外 操作系统,而不是其中)。

在Singularity OS项目中,Microsoft测量了在使用MMU保护而不是类型系统进行进程分离时对系统性能的影响约30%。

Azul在构建专用Java CPU时注意到的另一件事是,现代主流CPU在尝试降低缓存丢失的成本时将重点放在完全错误的事情上:他们尝试通过分支预测,内存预取,等等。但是,在高度多态的OO程序中,访问模式基本上是伪随机的,根本没有什么可预测的。因此,所有这些晶体管都被浪费掉了,而应该做的是减少每个缓存丢失的成本。(总成本是#misses *成本,主流试图降低第一个,而Azul则是第二个。)Azul的Java Compute Accelerators可能有20000个并发的高速缓存未命中,并且仍在取得进展。

Azul刚开始时,他们认为他们会采用一些现成的I / O组件并设计自己的专用CPU内核,但实际上最终需要做的恰恰相反:他们采用了相当标准的机架3地址RISC内核,并设计了自己的内存控制器,MMU和缓存子系统。

tl; dr:Python的“慢”不是该语言的属性,而是a)它的幼稚(主要)实现,以及b)现代CPU和OS专为使C快速运行而设计的事实,以及它们的功能C语言的使用要么没有帮助(缓存),要么甚至是在损害(虚拟内存)Python性能。

而且,您可以在这里插入几乎任何具有动态即席多态性的内存管理语言…当谈到有效实现的挑战时,甚至Python和Java几乎都是“同一种语言”。


您是否有Azul的链接或参考?
Basile Starynkevitch 2016年

4
我不同意一种语言的语义对其有效实施的能力没有影响。是的,具有一流的优化和分析的良好JIT实现可以极大地改善语言的性能,但是最终,语义的某些方面将不可避免地成为瓶颈。无论是C严格要求指针别名,还是Python要求原子执行列表操作,都存在某些语义决定,这些决定不可避免地会损害某些应用程序的性能。
Jules

1
顺便说一句...您对奇点性提高30%有参考吗?我多年来一直倡导基于语言的保护操作系统,但以前从未见过该数字,并且感到非常吃惊(我过去看过的数字接近10%),并且想知道是什么他们确实取得了很大的进步……
朱尔斯

5
@MasonWheeler:因为那里只有糟糕的Python实现。没有Python实施者花了很小一部分钱,人员,研究和资源,IBM,Sun,Oracle,Google和Co.花费在J9,JRockit,HotSpot和Co上。所有这5种Python实现的总和甚至都没有拥有Oracle仅在垃圾收集器上花费的人力。IBM正在开发基于Eclipse OMR(从J9提取的组件化的开源虚拟机架构)Python实现,我敢打赌,它的性能将J9的数量级内很好
约尔格W¯¯米塔格

2
对于记录而言,由于Fortran强制执行严格的别名,因此与Fortran相比,C的计算速度慢
Michael Shopsin '16

8

尽管Python当前的实现(缺乏其他动态语言执行的许多优化,例如现代Javascript实现以及您所指出的Lua)是其大多数问题的根源,但确实存在一些语义上的问题使得它成为现实。至少在某些领域,实现难以与其他语言竞争。一些值得特别考虑的问题:

  • 语言定义要求列表和字典操作是原子的。这意味着除非JIT编译器能够证明没有对列表对象的引用逃脱了其当前线程(这种分析在许多情况下是困难的,而在一般情况下是不可能的),则必须确保对对象的访问已序列化(例如,通过锁定)。CPython实现通过使用臭名昭著的“全局解释器锁”解决了此问题,该阻止了Python代码在具有多线程技术的多处理环境中有效地使用,尽管其他解决方案都有可能出现性能问题。

  • Python没有指定值对象使用的机制。一切都通过引用来处理,在不必要的地方添加了额外的间接。尽管在某些情况下JIT编译器可能会推断出值对象并自动对其进行优化,但通常无法这样做,因此,未经仔细编写以确保可能进行优化的代码(这有点荒唐)会受苦的。

  • Python具有一个eval功能,这意味着JIT编译器即使执行一次整个程序分析,也不能对未发生的动作做出假设,只要eval使用一次即可。例如,Python编译器不能假设一个类没有子类,因此不能虚化方法调用,因为该假设以后可以通过调用来否定eval。相反,它必须执行动态类型检查,以确保在执行本机代码之前,由本机编译的代码所做的假设未失效。


3
可以通过eval触发重新编译和/或去优化来减轻后一点。
约尔格W¯¯米塔格

4
顺便说一下,这也不是Python独有的。Java(或JVM)具有动态代码加载和动态链接功能,因此Class Hierarchy Analysis等效于在那里解决Halting问题。但是,HotSpot高兴地推测性地内联了多态方法,并且,如果类层次结构中的某些内容发生了变化,那么它将直接取消内联它们。
约尔格W¯¯米塔格
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.