为什么Python和Ruby这么慢,而Lisp实现速度很快?

ith*_*isa 23 ruby lisp python performance scheme

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

为什么会这样?我经常听到有人说慢速是你为动态语言付出的代价,但是Lisps非常动态并且速度不是很慢(它们通常比C慢不到5倍; Ruby和Python可以达到两位数).此外,Lisp样式使用递归,并不总是尾递归,很多,堆栈是堆中的连续的链接列表等,这似乎应该使Lisp比命令式样式的Python和Ruby慢.

Racket和SBCL是JITted,但Chicken Scheme要么是静态编译的,要么使用非优化的解释器,这两种解释器都应该非常适合动态语言并且速度慢.即使使用了csiChicken Scheme 的天真解释器(甚至不进行字节码编译!),我的速度远远超出了Python和Ruby.

与类似的动态Lisps相比,为什么Python和Ruby的速度如此之慢?是因为它们是面向对象的,需要巨大的vtable和类型heirarchies?

示例:阶乘函数.蟒蛇:

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

for x in xrange(10000000):
    i = factorial(10)
Run Code Online (Sandbox Code Playgroud)

球拍:

#lang racket

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

(define q 0)

(for ([i 10000000])
  (set! q (factorial 10)))
Run Code Online (Sandbox Code Playgroud)

时间结果:

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
Run Code Online (Sandbox Code Playgroud)

Rai*_*wig 17

编译的Lisp系统通常比Ruby或Python快得多.

例如,参见Ruby和SBCL的比较:

http://benchmarksgame.alioth.debian.org/u32/benchmark.php?test=all&lang=yarv&lang2=sbcl&data=u32

或Python和SBCL:

http://benchmarksgame.alioth.debian.org/u32/benchmark.php?test=all&lang=python3&lang2=sbcl&data=u32

但请记住以下内容:

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

一些操作可能看起来相似,但可能不同.for迭代遍历整数变量的循环是否与循环遍历for范围的循环完全相同?

  • @John9631:“解释的Python”实际上是编译的:https://docs.python.org/devguide/compiler.html (2认同)

Ale*_*x D 12

Ruby/Python/etc中的方法调度很昂贵,而Ruby/Python/etc程序主要通过调用方法来计算.甚至forRuby中的循环也只是方法调用的语法糖each.