8

我编写了一个简单的斐波那契测试程序来比较 node.js 和 python 的性能。原来python用了5s完成计算,而node.js在200ms结束 为什么python在这种情况下表现这么差?

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

节点.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);
4

5 回答 5

13

像这样建立一个人为的基准并获得足够有用的结果来对速度做出笼统的陈述是不可能的;基准测试非常复杂,在某些情况下,运行时甚至可以完全排除基准测试的一部分,因为他们意识到有一种更快的方法来做你告诉它你想做的事情。

但是,底线是您不是在比较 Python 和 node.js,而是比较它们的解释器:CPython 和 V8。Python 和 Javascript 具有类似的影响性能的语言特性(垃圾收集、动态类型,甚至我认为的整数的堆分配?)所以当你运行这个基准测试时,它真的是解释器之间的枪战。

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

因此,如果您想要直接比较,请尝试在 PyPy 上运行您的 Python 代码,PyPy 是一个带有 JIT 的 Python 解释器。或者尝试在没有 JIT 的运行时运行您的 Javascript 代码。然而,到那时,您可能会发现基准测试太难太复杂,无法使用这样的脚本来判断哪种语言更快。

于 2013-10-11T02:04:58.943 回答
9

Node 使用JIT 编译器,该编译器旨在注意何时使用相同类型的输入多次运行相同的代码块并将其编译为机器代码。有可能 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
于 2013-10-11T02:05:16.710 回答
5

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

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);

看起来 javascript 方面没有性能改进,这往往表明这里已经内置了某种 memoization 机制。

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

于 2013-10-11T01:45:26.013 回答
2

我会把它写成评论,但由于我还没有足够的分数来这样做,所以我添加了另一个答案。

由于许多答案/评论都提到了 pypy,现在比原始问题的日期晚了几年,我想我会更新最新版本的CPython和运行 python 代码的pypy从问题:

Windows 7 64 位,英特尔至强 E5-1607 3GHz。

U:>python --version
Python 2.7.5

U:>python fib.py
9227465
3.54921930198

U:>pypy --version
Python 2.7.3 (2cec7296d7fb, Nov 12 2013, 13:24:40)
[PyPy 2.2.0 with MSC v.1500 32 位]

U:>pypy fib.py
9227465
0.385597246386

因此,在这个微基准测试中,此时pypyCPython9 倍多。看起来 node.js 仍然会更快。

干杯,蒂姆。

于 2013-11-15T10:21:42.090 回答
-1

有一种方法可以通过使用 lru_cache() 装饰器来加速 Cpython 的递归。然后,结果会比 NodeJS 更快。在下面的链接中找到有关递归和 lru_cache() 的更多信息。

https://realpython.com/lru-cache-python/#using-lru_cache-to-implement-an-lru-cache-in-python

https://realpython.com/python-thinking-recursively/

from functools import lru_cache
import time
beg = time.time()

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

C:\Users\steps\Desktop>python dot.py 
9227465
0.0
于 2021-05-30T12:17:41.820 回答