为什么Python在这个简单“测试”中比Ruby慢?
可以查看 这个链接,了解我之前对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 个回答
在我朋友的笔记本电脑上(Windows7 64位,python 2.6,3GB内存),处理6553500这个数字大约只需要1秒,而处理65535000这个数字则需要10秒。我很好奇为什么你的电脑要花这么多时间。当我使用xrange和局部变量时,处理更大的输入也能节省一些时间。
至于Ruby,我无法评论,因为这台电脑上没有安装它。
为什么会这样呢?
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
首先要注意,你展示的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
里的。而局部变量可以通过索引直接被虚拟机引用,所以不需要查找哈希表。
另外要注意,这个测试非常简单,你实际上是在对几个任意的字节码操作进行基准测试。