我发现在Python和Ruby中,函数调用和循环之类的简单事情,甚至只是循环递增一个计数器所需的时间都比Chicken Scheme、Racket或SBCL中的要长。
为什么会这样?我经常听到人们说,慢是动态语言的代价,但是lisp是非常动态的,并不是非常慢(它们通常比C慢不到5倍;Ruby和Python可以达到两位数)。此外,Lisp风格使用递归,并不总是尾部递归,很多情况下,堆栈是堆中连续性的链表,等等,这似乎会使Lisp比命令式Python和Ruby慢。
Racket和SBCL是JITted的,但是Chicken Scheme要么是静态编译的,要么是使用非优化的解释器,这两种解释器都不适合动态语言,而且速度慢。然而,即使使用Chicken Scheme的天真的csi
解释器(它甚至不进行字节码编译!),我的速度远远超过Python和Ruby。
与类似的动态lisp相比,Python和Ruby到底为什么慢得可笑?是不是因为它们是面向对象的,需要巨大的vtable和类型继承器?
例如:阶乘函数。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
我不知道您的racket安装,但如果运行时没有标志,我只是
apt-get install
使用JIT编译的racket。使用--no-jit
运行会使时间更接近Python时间(racket
:3s,racket --no-jit
:37s,python
:74s)。此外,由于语言设计的原因,模块范围内的赋值比Python中的本地赋值慢(非常自由的模块系统),将代码移到一个函数中会使Python处于60秒。剩下的差距可能可以解释为一些巧合、不同优化焦点的组合(函数调用在Lisp中必须非常快,Python人不太在意)、实现质量(ref计数与正确的GC、stack VM与register VM)等等,而不是各自语言设计的基本结果。编译后的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
但请记住以下几点:
另外,一些操作可能看起来相似,但可能不同。迭代整数变量的
for
循环真的和迭代范围的for
循环一样吗?Ruby/Python/etc中的方法调度非常昂贵,Ruby/Python/etc程序主要通过调用方法进行计算。甚至Ruby中的
for
循环对于对each
的方法调用来说也是语法糖。相关问题 更多 >
编程相关推荐