为什么Python在这个简单“测试”中比Ruby慢?

2 投票
4 回答
1764 浏览
提问于 2025-04-16 06:23

可以查看 这个链接,了解我之前对Python和Ruby之间差异的理解。

正如igouy所指出的,我认为Python运行慢的原因可能不仅仅是因为递归函数调用(涉及到栈的问题)。

我做了这个

#!/usr/bin/python2.7
i = 0
a = 0
while i < 6553500:
    i += 1
    if i != 6553500:
       a = i 
    else:
        print "o" 
print a 

在Ruby中是

#!/usr/bin/ruby
i = 0
a = 0
while i < 6553500
    i += 1
    if i != 6553500
       a = i 
    else
        print "o"
    end
end   
print a

这是Python 3.1.2的版本信息(r312:79147,2010年10月4日,12:45:09) [GCC 4.5.1] 在linux2上运行

运行命令:time python pytest.py

结果是

6553499

实际时间 0m3.637s

用户时间 0m3.586s

这是Ruby 1.9.2p0的版本信息(2010-08-18 修订版 29036) [x86_64-linux] 运行命令:time ruby rutest.rb

结果是

o6553499

实际时间 0m0.618s

用户时间 0m0.610s

让它循环更多次会导致更大的差异。多加一个0,Ruby完成需要7秒,而Python则需要40秒。

这是在Intel(R) Core(TM) i7 CPU M 620 @ 2.67GHz,内存4GB的电脑上运行的。

这到底是为什么呢?

4 个回答

1

在我朋友的笔记本电脑上(Windows7 64位,python 2.6,3GB内存),处理6553500这个数字大约只需要1秒,而处理65535000这个数字则需要10秒。我很好奇为什么你的电脑要花这么多时间。当我使用xrange和局部变量时,处理更大的输入也能节省一些时间。

至于Ruby,我无法评论,因为这台电脑上没有安装它。

2

为什么会这样呢?

Python的循环(比如for和while)在处理动态类型时速度比较慢。在这种情况下,它就失去了优势。

但是Cython成了救星。
下面的纯Python版本是借鉴自Glenn Maynard的回答(没有打印输出)。
Cython版本在这个基础上非常简单,连新手Python程序员都能看懂:

def main():
    cdef int i = 0
    cdef int a = 0
    while i < 6553500:
        i += 1
        if i != 6553500:
            a = i
        else:
            pass  # print "0"
    return a

if __name__ == "__main__":
    print main()

在我的电脑上,Python版本需要2.5秒,而Cython版本只需要5.5毫秒:

In [1]: import pyximport

In [2]: pyximport.install()

In [3]: import spam  # pure python version

In [4]: timeit spam.main()
1 loops, best of 3: 2.41 s per loop

In [5]: import eggs  # cython version

In [6]: timeit eggs.main()
100 loops, best of 3: 5.51 ms per loop

更新:正如Glenn Maynard在评论中指出的,while i < N: i+= 1并不是很Pythonic(不太符合Python的风格)。
我测试了xrange的实现。
spam.py和Glenn Maynard的版本是一样的。foo.py的代码是:

def main():
    for i in xrange(6553500):
        pass
    a = i
    return a

if __name__ == "__main__":
    print main()
~/code/note$ time python2.7 spam.py  # Glenn Maynard's while version
6553499

real    0m2.128s
user    0m2.080s
sys     0m0.044s
:~/code/note$ time python2.7 foo.py  # xrange version, as Glenn Maynard point out in comment
6553499

real    0m0.618s
user    0m0.604s
sys     0m0.016s
16

首先要注意,你展示的Python版本是错误的:你实际上是在运行Python 2.7,而不是3.1(这甚至不是有效的Python 3代码)。顺便说一下,Python 3通常比2慢。

话虽如此,你的Python测试有一个关键问题:你把它写成了全局代码。你需要把它写成一个函数。这样写的话,无论是在Python 2还是3中,运行速度大约会快两倍:

def main():
    i = 0
    a = 0
    while i < 6553500:
        i += 1
        if i != 6553500:
           a = i
        else:
            print("o")
    print(a)

if __name__ == "__main__":
    main()

当你写全局代码时,你没有局部变量;你所有的变量都是全局变量。在Python中,局部变量的访问速度比全局变量快,因为全局变量是存储在一个dict里的。而局部变量可以通过索引直接被虚拟机引用,所以不需要查找哈希表。

另外要注意,这个测试非常简单,你实际上是在对几个任意的字节码操作进行基准测试。

撰写回答