Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Python和Ruby速度如此之慢,而Lisp实现速度如此之快?_Python_Ruby_Performance_Scheme_Lisp - Fatal编程技术网

为什么Python和Ruby速度如此之慢,而Lisp实现速度如此之快?

为什么Python和Ruby速度如此之慢,而Lisp实现速度如此之快?,python,ruby,performance,scheme,lisp,Python,Ruby,Performance,Scheme,Lisp,我发现在Python和Ruby中,像函数调用和循环这样的简单事情,甚至只是循环递增计数器,都比在Chicken Scheme、Racket或SBCL中花费的时间要多得多 为什么会这样?我经常听到人们说,速度慢是为动态语言付出的代价,但是Lisp是非常动态的,速度也不是很慢(通常比C慢不到5倍;Ruby和Python可以达到两位数)。此外,Lisp风格使用递归,而不总是尾部递归,很多情况下,堆栈是堆中连续的链表,等等,这似乎使Lisp比命令式Python和Ruby更慢 Racket和SBCL是JI

我发现在Python和Ruby中,像函数调用和循环这样的简单事情,甚至只是循环递增计数器,都比在Chicken Scheme、Racket或SBCL中花费的时间要多得多

为什么会这样?我经常听到人们说,速度慢是为动态语言付出的代价,但是Lisp是非常动态的,速度也不是很慢(通常比C慢不到5倍;Ruby和Python可以达到两位数)。此外,Lisp风格使用递归,而不总是尾部递归,很多情况下,堆栈是堆中连续的链表,等等,这似乎使Lisp比命令式Python和Ruby更慢

Racket和SBCL是JITted的,但chickenscheme要么是静态编译的,要么使用非优化解释器,这两种解释器都不适合动态语言,而且速度较慢。然而,即使使用幼稚的
csi
鸡肉模式解释器(它甚至不进行字节码编译!),我的速度也远远超过了Python和Ruby

为什么Python和Ruby与类似的动态Lisp相比速度如此之慢?是因为它们是面向对象的,需要庞大的vtables和类型继承器吗

示例:阶乘函数。Python:

def factorial(n):
    if n == 0:
        return 1
    else:
    return n*factorial(n-1)

for x in xrange(10000000):
    i = factorial(10)
球拍:

#lang racket

(define (factorial n)
  (cond
   [(zero? n) 1]
   [else (* n (factorial (sub1 n)))]))

(define q 0)

(for ([i 10000000])
  (set! q (factorial 10)))
计时结果:

ithisa@miyasa /scratch> time racket factorial.rkt
racket factorial.rkt  1.00s user 0.03s system 99% cpu 1.032 total
ithisa@miyasa /scratch> time python factorial.py
python factorial.py  13.66s user 0.01s system 100% cpu 13.653 total

我认为,与其说Python本身很慢,不如说是Python解释器以较慢的速度遍历代码。如果您试图用py2exe之类的工具编译代码,那么它可能比lisp更快。您必须尝试一下,但我认为它的解释器速度很慢。

我不知道您的racket安装情况,但我刚刚安装的racket如果在没有标志的情况下运行,将使用JIT编译。使用
--no-jit
运行会使时间更接近Python时间(
racket
:3s,
racket--no-jit
:37s,
Python
:74s)。此外,由于语言设计的原因(非常自由的模块系统),模块范围内的赋值比Python中的本地赋值慢,将代码移动到函数中会使Python处于60年代。剩下的差距可能可以解释为巧合、不同的优化重点(函数调用在Lisp中必须非常快,Python人员不太关心)、实现质量(引用计数与正确GC、堆栈VM与寄存器VM)的组合,等,而不是各自语言设计的基本结果。

本机编译的Lisp系统通常比非本机编译的Lisp、Ruby或Python实现快很多

定义:

  • 本机编译->编译为机器代码
  • 编译->编译为机器代码或其他目标(如字节码、JVM指令、C代码等)
  • 解释Lisp->直接运行s表达式,无需编译
  • 解释型Python->在字节码解释器中运行编译后的Python。默认的Python实现并不是真正解释的,而是使用编译器对字节码指令集进行编译。字节码被解释。通常,字节码解释器比本机代码的执行速度慢
但请记住以下几点:

  • SBCL使用本机代码编译器。它不使用字节码机器或类似JIT编译器的东西,从字节码到本机代码。SBCL在运行前将所有代码从源代码编译为本机代码。编译器是增量的,可以编译单个表达式。因此,它也被EVAL函数和Read EVAL Print循环使用
  • SBCL使用一个优化编译器,它使用类型声明和类型推断。编译器生成本机代码
  • Common Lisp允许各种优化,使代码不那么动态或不动态(内联、早期绑定、无类型检查、专用于声明类型的代码、尾部调用优化等)。使用这些高级功能的代码可能看起来很复杂,尤其是当需要告诉编译器这些事情时
  • 如果没有这些优化,编译的Lisp代码仍然比解释的代码快,但比优化的编译代码慢
  • CommonLisp提供CLOS,即CommonLisp对象系统。CLOS代码通常比非CLOS代码慢——这一比较是有意义的。动态函数式语言往往比动态面向对象语言更快
  • 如果语言实现使用高度优化的运行时,例如用于bignum算术运算,那么速度较慢的语言实现可能比优化编译器更快。有些语言有许多用C实现的复杂原语。这些原语往往很快,而语言的其他部分可能很慢
  • 还有一些Python的实现,它们生成并运行机器代码,比如PyPy的JIT编译器。自从Ruby 2.6以来,Ruby现在也有了一个JIT编译器

此外,一些操作可能看起来相似,但可能不同。迭代整数变量的
for
循环真的与迭代一个范围的
for
循环相同吗?

Ruby/Python/etc中的方法调度非常昂贵,Ruby/Python/etc程序主要通过调用方法进行计算。即使Ruby中的
for
循环也只是对
的方法调用的语法糖,每个

Python都是由CPython解释器定义的。此外,我尝试了pypy,但它只是优化了整个循环,因为它没有任何可见的副作用。@user54609,然后尝试
q+=factorial(10)
在末尾打印q
,我强烈怀疑py2exe能否消除这种差异。解释开销是可以测量的,但远没有那么大,Lisp解释器也会有解释开销(尽管确切的值当然会有所不同)。事实上我不认为py2exe会删除解释,