开发者

Why is python slower compared to Ruby even with this very simple "test"?

开发者 https://www.devze.com 2023-01-22 16:35 出处:网络
See Is there something wrong with this python code, why does it run so slow compared to ruby? for my previous attempt at understanding the differences between python and ruby.

See Is there something wrong with this python code, why does it run so slow compared to ruby? for my previous attempt at understanding the differences between python and ruby.

As pointed out by igouy the reasoning I came up with for python being slower could be something else than due to recursive function calls (stack involved).

I made this

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

In ruby it is

#!/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, Oct 4 2010, 12:45:09) [GCC 4.5.1] on linux2

time python pytest.py o

6553499

real 0m3.637s

user 0m3.586s

ruby 1.9.2p0 (2010-08-18 revision 29036开发者_JS百科) [x86_64-linux] time ruby rutest.rb

o6553499

real 0m0.618s

user 0m0.610s

Letting it loop higher gives higher differences. Adding an extra 0, ruby finishes in 7s, while python runs for 40s.

This is run on Intel(R) Core(TM) i7 CPU M 620 @ 2.67GHz with 4GB mem.

Why is this so?


First off, note that the Python version you show is incorrect: you're running this code in Python 2.7, not 3.1 (it's not even valid Python3 code). (FYI, Python 3 is usually slower than 2.)

That said, there's a critical problem in the Python test: you're writing it as global code. You need to write it as a function. It runs about twice as fast when written correctly, in both Python 2 and 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()

When you write code globally, you have no locals; all of your variables are global variables. Locals are much faster than globals in Python, because globals are stored in a dict. Locals can be referenced directly by the VM by index, so no hash table lookups are needed.

Also, note that this is such a simple test, what you're really doing is benchmarking a few arbitrary bytecode operations.


Why is this so?

Python's loop (for, while) isn't fast for handle dynamic types. in such a case, it lose the advantage.

but cython becames the salvation
pure python version below borrowed from Glenn Maynard's answer (without print)
cython version is very easy based on this, it's is easy enough for a new python programmer can read :

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

on my pc, python version need 2.5s, cython version need 5.5ms:

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

update: as Glenn Maynard point out in the comment, while i < N: i+= 1 is not pythonic.
I test xrange implementation.
spam.py is the same as Glenn Maynard's verison. foo.py's code is:

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


On my friend's laptop (Windows7 64 bit, python 2.6, 3GB RAM), python takes only around 1 sec for 6553500 and 10 secs for 65535000 input. I wonder why your computer is taking so much time. It also shaves off some time on the larger input when I use xrange and local variables instead.

I cannot comment on Ruby since it's not installed on this computer.


It's too simple test. Maybe in such things Ruby is faster. But Python takes advantage, when you need to work with more complex datatypes and their methods. Python have much more implemented "ways to do this", and you must choose the one, which is the simplest and enough. Ruby works with more abstract entities and it requires less knowledge. But when it is possible in the same task in Python go deeper in it's manuals and find more and more combinations of types and methods/functions, it is possible after time to make much more faster program, than Ruby.

Ruby is simplier and easier to write, if you just want to get result, not perfomance. But the more complex you task is, the more advantage Python will have in perfomance after hours of optimizing.

UPD: While Ruby and Python have so much common things, the perfomace and high-levelness will have the reverse proportionality.

0

精彩评论

暂无评论...
验证码 换一张
取 消