为什么Python在recursion上比node.js慢得多

我写了一个简单的斐波那契testing程序来比较node.js和python的性能。 事实certificate,python花了5s来完成计算,而node.js在200ms结束为什么python在这种情况下performance如此糟糕?

python

import time beg = time.clock() def fib(n): if n <=2: return 1 return fib(n-2) + fib(n-1) var = fib(35) end = time.clock() print var print end - beg 

的node.js

 var beg = new Date().getTime(); function fib(n) { if (n <= 2) return 1; return fib(n-2) + fib(n-1); } var f = fib(35); var end = new Date().getTime(); console.log(f); console.log(end - beg); 

build立这样一个人为的基准是不可能的,并且得到足够有用的结果来对速度进行一揽子的陈述; 基准testing是非常复杂的,在某些情况下,运行时甚至可以将基准testing的部分因素完全分解出来,因为他们意识到有一种更快的方法来做你所要做的事情。

但是,最重要的是,您不是将Python与node.js进行比较,而是将它们的解释器进行比较:CPython与V8。 Python和Javascript有类似的语言特性,会影响性能(垃圾收集,dynamictypes,甚至整数的堆分配,我认为?),所以当你运行这个基准testing时,它确实是解释器之间的枪战。

在这种情况下,即使像这样的基准testing通常是没有价值的,但是“为什么V8比CPython在这类事情上更快”这个问题有一个答案: 这是因为JIT编译器

所以,如果你想直接比较,试着在PyPy上运行你的Python代码,这是一个带有JIT的Python解释器。 或者尝试在没有JIT的运行时上运行你的Javascript代码。 然而,在这一点上,你可能会发现基准testing太难,太复杂,不能用这样的脚本来判断哪种语言更快。

节点使用JIT编译器 ,该编译器devise用于注意同一代码块多次运行相同types的input并将其编译为机器码。 Node甚至有可能注意到这是一个纯粹的函数和内联的一些结果,但是从这种编译器的本质来看,这是很难从外部看出来的。

CPython是一个天真的解释器,并将完全按照你所说的去做。 然而,正在尝试编写一个名为PyPy的Python JIT(用Python编写,正如你所看到的那样),结果很有希望:

 $ time python2 fib.py 9227465 python2 fib.py 2.90s user 0.01s system 99% cpu 2.907 total $ time pypy fib.py 9227465 pypy fib.py 1.73s user 0.03s system 96% cpu 1.816 total 

如果你在Python中使用memoized的斐波那契函数,你会发现它变得更快:

 import time beg = time.clock() def memoize(f): cache = {} def decorated_function(*args): if args in cache: return cache[args] else: cache[args] = f(*args) return cache[args] return decorated_function @memoize def fib(n): if n <=2: return 1 return fib(n-2) + fib(n-1) var = fib(35) end = time.clock() print(var) print(end - beg) 

你可以在JavaScript中做同样的事情:

 function memoize( fn ) { return function () { var args = Array.prototype.slice.call(arguments), hash = "", i = args.length; currentArg = null; while (i--) { currentArg = args[i]; hash += (currentArg === Object(currentArg)) ? JSON.stringify(currentArg) : currentArg; fn.memoize || (fn.memoize = {}); } return (hash in fn.memoize) ? fn.memoize[hash] : fn.memoize[hash] = fn.apply(this, args); }; } var beg = new Date().getTime(); function fib(n) { if (n <= 2) return 1; return fib(n-2) + fib(n-1); } var f = memoize(fib)(35); var end = new Date().getTime(); console.log(f); console.log(end - beg); 

它看起来像没有性能改善的一面,这往往表明,这里已经有某种内置的memoization机制。

学分: http : //ujihisa.blogspot.fr/2010/11/memoized-recursive-fibonacci-in-python.html,http : //addyosmani.com/blog/faster-javascript-memoization/

我会写这个作为一个评论,但由于我还没有足够的要点这样做,我已经增加了另一个答案。

由于许多答案/评论都提到了pypy ,现在比原始问题的date晚了两年,我想我会给出最新版本的CPython和pypy的更新,题:

Windows 7 64位,Intel Xeon E5-1607 3GHz。

U:> python –version
Python 2.7.5

U:> python fib.py
9227465
3.54921930198

U:> pypy – 版本
Python 2.7.3(2cec7296d7fb,Nov 12 2013,13:24:40)
[PyPy 2.2.0与MSC v.1500 32位]

U:> pypy fib.py
9227465
0.385597246386

所以在这个时候,在这个微观基准testing中, pypy比CPython快了9倍 。 它仍然看起来像node.js会更快。

干杯,蒂姆。