Tested: Ruby vs Python Speed (in numbers)

I’ve been looking for a while for specifics on how one of my favorite
languages, Ruby, performs relative to its most comparable (and, to an
extent, rival) language, Python. However, I was never able to find any
specifics, or really, anything beyond hearsay or biased conjecture. So I
decided to do some research myself.

TL;DR
If you don’t want to read an entire lab thesis, skip to the bottom for a
conclusion, and number analyses.

So, I present to you: Ruby vs. Python; A speed test with actual numbers.

For the record, I used an Asus laptop with dual 5400RPM hard disks, and
an Intel Core i7-3630QM CPU with 4 cores, 8 threads, and a factory clock
speed of 2.40MHz, not overclocked, running Windows 8.1 64-Bit. (I would
usually be doing this on Fedora Linux, but Bill Gates went pretty
monkey-attack mode on secondary systems for Win 8.) I am also running
the stock, default interpreter for each language. Python was running
version 3.4.2, and Ruby on version 2.1.4.

Test 1: The ‘for’ Loop

The first test was a VERY simple one; an old fashioned ‘for’ loop. This
was just to test RAW speed of the interpreters, and the looping
structure.

Here’s the Ruby code I ran:

t = Time.now.to_f
for i in 1…1000000
puts i
end
puts "Elapsed time: ", Time.now.to_f - t

And the Python Equivalent:

import time
t = time.time()
for i in range(1, 1000000):
print(i)
print("Elapsed time: ", time.time() - t)

They printed out each value between 1 and 999,999, then spat out the
number of seconds it took. I did 4 tests for each language, with Python
going first for each set. (Python, Ruby, Python, Ruby…) The times were
very similar within each language, so there didn’t seem to be any
problems outside of the languages themselves.

Ruby average time: 69.49673 seconds
Python average time: 45.61045 seconds
Ruby to Python speed ratio: 1 : 0.6563
Python to Ruby speed ratio: 1 : 1.5237

Ruby’s time, as I had expected after what I had heard on some
programming forums, was noticeably slower, by about 50%. This wasn’t
enough to make me want to stop using Ruby by any means, but it
definitely was something to take into consideration for speed sensitive
tasks that you don’t want to write in C.

Test 2: Recursion and Subroutines

I decided that it would be good form to try another test, and see what
the results would be if I tried recursion. I knew it would be a better
gauge of method calling efficiency, resource management, and real-world
performance. I predicted that Python would still beat Ruby out, but by a
lesser margin, maybe 25% rather than 50, due to Ruby’s slightly simpler
design. So I wrote scripts that found the 40th number in the Fibonacci
Sequence. (Starting at 0, obviously)

Ruby Code:

def fibonacci(i)
if i < 2
return i
else
return fibonacci(i-2) + fibonacci(i-1)
end
end
t = Time.now.to_f
puts fibonacci(40)
puts "Elapsed time: ", Time.now.to_f - t

Python Code:

import time
def fibonacci(i):
if i < 2:
return i
else:
return fibonacci(i-2) + fibonacci(i-1)
t = time.time()
print(fibonacci(40))
print("Elapsed time: ", time.time() - t)

Again, they printed out the 40th Fibonacci number, and how many seconds
it took to figure it out. I decided to use ‘if’ statements with ‘return’
statements inside, rather than ‘return if’ statements to eliminate as
many variables between the languages as possible. This time, Ruby went
first for each test. (Ruby, Python, Ruby, Python…) And again, the
times were very similar within each language.

Ruby average time: 15.60163 seconds
Python average time: 54.91850 seconds
Ruby to Python speed ratio: 1 : 3.5200
Python to Ruby Speed ratio: 1 : 0.2841

I was VERY surprised by this test. Although Python was a full 50% faster
as far as raw speeds went in the ‘for’ loop test, Ruby BLASTED through
this test at 15 seconds, and left Python in the dust with 55 seconds,
almost a full minute! But the test had me scratching my head. How is it
possible that Ruby was almost 4 times faster than Python, despite a
slower raw speed? Simple architecture? Efficient subroutine calling?
Flawless resource management? More utilization of threads? Whatever the
case may be, I was pretty impressed by the MRI.

Conclusion
Python has a notably higher raw speed than Ruby, being 50% faster in a
simple ‘for’ loop test. However, neither are blazing fast, and C should
really be used for anything that speed-dependent. However, Ruby was
light-years ahead of Python when it came to the recursion test. This is
much heavier on the use of subroutines, resources, “multitasking,” value
returns, and real-world performance as a whole.

‘for’ Loop Test:

Ruby average time: 69.49673 seconds
Python average time: 45.61045 seconds
Ruby to Python speed ratio: 1 : 0.6563
Python to Ruby speed ratio: 1 : 1.5237

Recursion and Subroutine Test:

Ruby average time: 15.60163 seconds
Python average time: 54.91850 seconds
Ruby to Python speed ratio: 1 : 3.5200
Python to Ruby Speed ratio: 1 : 0.2841

Thanks, and I hope some of you find this useful.
-RJ

  • be aware you are not comparing Ruby vs Python but one of their
    respective implementations (CRuby vs CPython)
  • in the first example you are measuring standard output throughput
    rather the language constructs effectiveness
  • in the first example using for' loops is not idiomatic to Ruby and should be usually written in form (1…1000000).each { puts i }', which
    is even about 10% faster on my machine
  • it is a commonly known fact function calls in CPython are expensive
    both in 2.x and 3.x branches
  • even non-recursive fibonacci is about 20% faster in recent CRuby then
    in CPython here

For the inspiration with more relevant benchmarks you should visit
http://benchmarksgame.alioth.debian.org/ site. Besides importance of
such and similar benchmarks is rather marginal for the practical use, it
looks like YARV Ruby become generally a bit faster at a bit lower memory
usage then current CPython.

be aware you are not comparing Ruby vs Python but one of their
respective implementations (CRuby vs CPython)
I’m well aware of that. I was doing a test of the default, reference
interpreters. They tend to be the most stable, “plain Jane”
implementations, and the most accurate representation of the language’s
specification itself.

in the first example you are measuring standard output throughput
rather the language constructs effectiveness
That’s what I meant by “raw speed.” Sorry for any mixups due to my poor
programming vocab! :wink:

in the first example using for' loops is not idiomatic to Ruby and should be usually written in form(1…1000000).each { puts i }’, which
is even about 10% faster on my machine
I wanted to use the exact same type of structure on each language. I
realize that your method is preferred, but if I used that, someone would
rebut the fact that I did essentially two vastly different things.
(Iterating directly from a range, rather then using a range attached to
a looping structure.) So I figured using ‘for’ loops would be the most
fair comparison, since they’re pretty much universal, and usually pretty
literal.

it is a commonly known fact function calls in CPython are expensive
both in 2.x and 3.x branches
Well, we got numbers! I’d heard that, but I actually didn’t think the
method calls would be that drastically slow in Python, but now I know.

even non-recursive fibonacci is about 20% faster in recent CRuby then
in CPython here
I can see that happening. I just wanted to use recursion, since it’s
very heavy on method calls, thread use, resources, and whatever else.
The fact that it found the Fibonacci sequence was pretty much just
because it was the first thing to pop into my head. I’m glad I used it
though. It did a great job of illustrating exactly how slow the Python
stock interpreter is in comparison to the MRI whenever you go anywhere
outside of the raw speed. (Or throughput speed, as you phrased it, which
is probably a more accurate description.) And I doubt many other
implementations are TONS faster if the default one is like this.

Thanks for replying. I might do another test sometime or another for
myself with your recommendations taken to heart. :slight_smile: