2

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) [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?

Community
  • 1
  • 1
rapadura
  • 5,242
  • 7
  • 39
  • 57

4 Answers4

16

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.

Glenn Maynard
  • 55,829
  • 10
  • 121
  • 131
  • 2
    It's just this case, and as AntonioP mentioned, function had not saved him. You dislike my answer, but it was about the main: "why ruby can be faster, than python?". I tried to answer fully, not just about this test program, and to make no need to explain every another program, which will give the author the same sonfusion. – Nakilon Nov 01 '10 at 11:05
  • It doesnt make ang big difference it if is python3 or python2.7, Ive tried both (adjusting the print to print function). So, using locals it went down to 2s for 6553500, but still 12s for 65535000, where ruby does it in 7s. – rapadura Nov 01 '10 at 11:06
  • @Nakilon: I realize that English is not your native language, but I simply can't understand you. – Glenn Maynard Nov 01 '10 at 11:07
  • @AntonioP: So, the bytecodes you happen to be stressing in this code are faster in Ruby than Python. It'd take delving deep into the VM engines of each to say exactly why, but I don't feel like doing that--I don't think it's very interesting, because neither of these code snippets are written in a way *natural* to either language. (... comment to be continued ...) – Glenn Maynard Nov 01 '10 at 11:19
  • @AntonioP: If we compare this code naturally--that is, writing it the way you'd *really* write it--change the Python loop to `for i in xrange(6553500):`. After doing that, the Python version is almost twice as fast (1sec to .6sec). I don't have Ruby1.9 installed to compare, but that seems to put them on parity based on your numbers. – Glenn Maynard Nov 01 '10 at 11:25
  • 1
    @AntonioP: By the way, I modified the Ruby version to also write it more naturally, to give each language a fair shot: `(0..6553500).each do |i|`. But after doing that, it became almost 2x *slower* than the C-esque version, which is bizarre. (But to be fair, I'm running it in 1.8, not 1.9.) – Glenn Maynard Nov 01 '10 at 11:27
  • @Glenn, I appreciate your comments and feedback. How is a programmer like me who comes from a C and Java background know what is the natural way for a language like python, which Im trying to learn now? The stuff I did so far is a combination of my previous programming knowledge. That is why I wanted to compare it with ruby, since Im curious about that language too. Speed is of importance for what I have planned to write, but there is no web-framework for C and the one for C++ I dont like. And Java is getting boring. – rapadura Nov 01 '10 at 11:44
  • 7
    @AntonioP: That's beyond the question, but just like any language: read the tutorial and documentation, and read and edit a lot of code. And: don't pick a high-level language based just on performance. Python is pretty fast among the dynamically-typed category of languages, but if that's all you look at you're going to miss its real feature set--comprehensions, generator functions and expressions, iterators, first-class functions, introspection, context managers, function and class decorators, not to mention the standard library. – Glenn Maynard Nov 01 '10 at 12:20
2

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
lotrpy
  • 403
  • 1
  • 4
  • 8
  • 2
    I consider cython a different language since you loose dynamic typing. – rapadura Nov 01 '10 at 11:45
  • 1
    @AntonioP, agree, cython is not python. the cython code is used to explain why python's foo/while loop is slow. – lotrpy Nov 01 '10 at 12:33
  • 5
    @AntonioP: No, cython doesn't lack dynamic typing. It adds *optional* static typing. But yes, it's not Python. –  Nov 01 '10 at 13:02
  • That is not correct. Cython is Python. Cython is not CPython. Cython allow both static and dynamic typing, you lose nothing. Cython is Python and any Python code will work under Cython with no change whatsoever, except some features that are not implemented in Cython.... yet! – Kilon Nov 11 '10 at 09:57
  • 1
    So apart from Cython having some features that CPython doesn't, and CPython having some features that Cython doesn't yet, they're the same language? I am not buying what you're selling. – Russell Borogove Nov 29 '10 at 20:13
1

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.

Tushar Tyagi
  • 211
  • 2
  • 12
  • Moreover different languages have different ways of implementing the same thing. Some of them work faster in one language then the other. These both program look same but using global variables and incrementing "i" seem to be the main bottleneck in the program. Maybe Ruby optimises it better than Python. – Tushar Tyagi Nov 01 '10 at 11:03
  • what kind of optimization does ruby perform? Why doesnt python do it? Can you install ruby and try it out if its not too much of a hassle? – rapadura Nov 01 '10 at 11:10
  • @AntonioP, they have different optimizations. You can look into their source code, if you want... ftp://ftp.ruby-lang.org//pub/ruby/1.9/ruby-1.9.2-p0.tar.gz and http://www.python.org/ftp/python/3.1.2/Python-3.1.2.tgz – Nakilon Nov 01 '10 at 11:16
-3

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.

Nakilon
  • 34,866
  • 14
  • 107
  • 142
  • 1
    In addition, global variables in Python are slow. If you put the same code in a function and call that function, it'll be a lot faster. – Thomas Wouters Nov 01 '10 at 10:43
  • 1
    I wasnt trying to conclude which language is "better" or a guide in which language I should use, just an explanation for this, and exactly (the above programs), difference in speed. I dont care about what each language as or doesnt or how it is supposed to be done. I just want to know what can influence the huge difference in speed for a very very simple program which looks exactly the same in both languages. @Thomas, I moved it to a function, still the same. – rapadura Nov 01 '10 at 10:49
  • 2
    I started to explain where this answer didn't make sense, then found that pretty much every sentence in this answer is nonsense, so I gave up... – Glenn Maynard Nov 01 '10 at 10:54
  • The code may *look* "exactly the same", but because the languages are in fact quite different, they're not actually the same. The semantics are different, even if you don't notice in the code because you're only relying on a small portion of the semantics. As for putting it in a function, see Glenn Maynard's answer. – Thomas Wouters Nov 01 '10 at 10:55
  • @AntonioP, as I said at the beginning, it's too simple test. It's not an ASM, and after compiling this program will have a lot of pages of machine code, which was processed by hundreds of different (really different for different languages) optimizations. If you could look into it's machine code, you would never think it was the same program ) – Nakilon Nov 01 '10 at 10:56