Alright the title of this post is a tad sensational sounding, I know, and it’s in part aimed at messing with my many Pythonista friends. We Rubyists have been teased for a long time, due to the slowness of the main Ruby interpreter. Well, it looks like with Ruby 1.9, it’ll be payback time. Just out of curiosity I decided to run a single benchmark (you can hardly call it that) to see how Ruby 1.9 had improved over the current stable version (1.8.6). I wasn’t planning to make a post about it. It was one of those tests that you do at 3 AM in an irb session when you feel you’ve made your daily peace with your actual workload for the night. When I saw the results though, my jaw dropped. I had to blog about this one.
I ran a recursive Fibonacci function, just to stress test a bit of recursion and method calling, and while I was at it, I decided to compare it with Python too. The test was run on Mac OS X 10.5 with my MacBook Pro (Core 2 Duo 2.2 GHz and 2 GB of memory). It’s a single test (which is obviously not a real world example, as you would use an iterative version of the function if it were), and unlike with real programs, it doesn’t stress many features of the language. At least for now, there is no reasonable evidence to conclude that Ruby 1.9 – which will be released for this coming Christmas – will actually be faster than Python 2.5.1 in the majority of situations, but hear me out and check out these very surprising results.
The Ruby code:
def fib(n)
if n == 0 || n == 1
n
else
fib(n-1) + fib(n-2)
end
end
36.times do |i|
puts "n=#{i} => #{fib(i)}"
end
And the Python equivalent:
def fib(n): if n == 0 or n == 1: return n else: return fib(n-1) + fib(n-2) for i in range(36): print "n=%d => %d" % (i, fib(i))
Running the snippets above, I got the following results:
Ruby 1.8.6: 158.869s
Python 2.5.1: 31.507s
Ruby 1.9.0: 11.934s
Ehm, hold on a second! Did Ruby just go from 159 seconds down to 12? Koichi Sasada, do you have an Amazon Wishlist? I was expecting a decent improvement, as I’ve been playing with 1.9 every now and then for a long time – so I knew it was faster – but I was blown away when I timed the latest version from trunk (even if it’s a really silly example that’s being tested). Granted Python is not the fastest language out there, but Ruby 1.9 was still able to execute the script almost 3 times as fast. It’s unbelievable.
Now it’ll be very interesting to run a series of algorithmically equivalent tests for Ruby and Python, and to see just when exactly Ruby 1.9 manages to knock Python out of the water – and where Python has still the edge. If I manage to find some time, I will report the results in this blog. But for now, I’ll say just… wow!
Get more stuff like this
Subscribe to my mailing list to receive similar updates about programming.
Thank you for subscribing. Please check your email to confirm your subscription.
Something went wrong.
I guess the difference between Ruby 1.9 and Python 2.5 mostly may comes from Python not optimizing tail-recursive calls (which btw is a design choice wrt/ ease of debugging, not a technical flaw).
But indeed, the speed-up between Ruby 1.8 and 1.9 is, well… wow !-)
What about psyco? have you tried it?
http://psyco.sourceforge.net/
There are lies, damn lies and Benchmarks… 😉
Does Ruby 1.9 optimize tail recursive calls? That’s great. Can you post a link where this is documented?
Bruno, I thought it might have been that at first, but the recursive calls aren’t tail calls.
Looks like Ruby’s function call overhead might be less than Python’s?
Bruno:
That function can’t be optimized by tail-recursive calls. Tail-recursion kicks in, only when your procedure is recursive, but process is iterative. Also, ruby never had any tail recursion.
The performance is mainly because of special handling of fixed point maths by new VM that Ruby 1.9 provides….
Oh yeah. The next sensational headline supported by an artificial benchmark. 🙂 But I’m more then happy, that ruby is getting faster, even though I turned away from it and back to my beloved Python.
As a Python user that has enjoyed doing some Ruby in the past, I’m glad to see that Ruby performance is improving. Congratulations! (I don’t get into the language wars. Python is the best solution for my current situation, but I admire Ruby.)
I imagine that like many I’m skeptical about the true level of improvement, I’m eager to see some more thorough benchmarks 🙂
But still, assuming it’s not a one off thing, that’s a pretty impressive speedup and could end up making Ruby much more competitive as an enterprise-level language.
Well of course I am biased since I use ruby and not python (but I never can understand a conflict between ruby and python, i am always saying to join up to beat on common enemies… perl and php and of course legacy shell scripts or solutions ESPECIALLY if they use perl 😉 )
But what can be roughly said is that it seems ruby-1.9 will be faster than 1.8, and this alone is the most important difference anyway!
I wholeheartedly agree with you Andrew.
“Mmmm.. yes fascinating,” he mumbles as he switches back to his vim window editing C source.
It is really goo to hear that as one of my main concerns today is ruby’s speed!
Thanks man!
Wow. I’m impressed by how much Ruby manages to uglify simple code snippets.
wow…Ruby is getting faster compared to python. But it doesnt mean, ruby is more powerful than python. anyway, i still love php. 😉
Reality check: C# 1.4 secs.
That’s cool thanks for sharing, i hope to do some benchamarks between 1.8 and 1.9
First, Ruby 1.9 has tail call analysis, but doesn’t use it for anything right now. They might include optimization later, but that’s not there yet.
General performance improvement for 1.9 is looking to be about 150% to 200% for most applications, based on more real world test cases.
Note that JRuby trunk now actually performs even better on recursive fib than Ruby 1.9.
Antonio, Python can calculate first 35 Fibo numbers in hundreds of times faster than Ruby. You just need to use right tools for right tasks. For example try to execute on your workstation:
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
f = fib()
for i in range(36):
print “n=%d => %d” % (i, f.next())
on my workstation it takes less than 0.1 second:
$ time python2.5 fibo.py
real 0m0.075s
user 0m0.020s
sys 0m0.028s
Yay, now you just need to take it to the next level. 😉
$ cat /proc/cpuinfo | grep name
model name : Intel(R) Pentium(R) III Mobile CPU 1133MHz
CL-USER> (defun fibo (n)
(if (<= (1- n) 0) n
(+ (fibo (- n 1)) (fibo (- n 2)))))
STYLE-WARNING: redefining FIBO in DEFUN
CL-USER> (defun test ()
(dotimes (i 36)
(format t "n=~a => ~a~%" i (fibo i))))
STYLE-WARNING: redefining TEST in DEFUN
CL-USER> (time (test))
[...]
Evaluation took:
7.734 seconds of real time
7.176449 seconds of user run time
0.004 seconds of system run time
0 calls to %EVAL
0 page faults and
212,424 bytes consed.
But, hey. We can do better.
CL-USER> (defun fibo (n)
(declare (optimize speed (safety 0) (debug 0))
(fixnum n))
(if (<= (1- n) 0) n
(the fixnum (+ (fibo (- n 1)) (fibo (- n 2))))))
STYLE-WARNING: redefining FIBO in DEFUN
CL-USER> (time (test))
[...]
Evaluation took:
2.129 seconds of real time
1.948121 seconds of user run time
0.0 seconds of system run time
0 calls to %EVAL
0 page faults and
179,528 bytes consed.
A language is fast, if the development progress is fast. This means C is slow, python and ruby are fast.
If the ruby interpreter can execute faster than python, the python folks will try to improve python.
I like python because the standard library is great and it has built in unicode support.
Does ruby1.9 give you built in unicode support?
Heh, day by day, python vs. ruby is becoming more like vi/emacs wars!
This just goes to prove how crap Python is. 😉
(BTW, what is Python?)
Ech, Python 2.4.4 + psyco gives: 2.5 sek 😀
On my PC, python takes 20 secs without psyco. With psyco, only 1.5 secs!
Well, since you’re comparing high-level languages… I quickly coded a silly implementation in Common Lisp.
(in-package #:cl-user)
(defun fib (n)
(declare (optimize (speed 3) (space 0) (safety 0) (debug 0)))
(if (or (eql n 0) (eql n 1))
n
(+ (fib (- n 1)) (fib (- n 2)))))
(time (loop for i from 0 to 35
do (format t “~A => ~A~&” i (fib i))))
; cpu time (total) 920 msec user, 10 msec system
; real time 924 msec
This is on the same type Macbook Pro that you’ve used, where the python version takes 31s.
I guess having a compiler (which can compile things entered interactively!) is a bit of an advantage. So I’m curious as to why people would still prefer languages without one.
–J.
And how about PHP 5 for good measure?
<?php
function fib($n)
{
if( $n == 0 || $n == 1 )
return $n;
else
return fib($n-1) + fib($n-2);
}
for( $i=0; $i #’.fib($i).”\n”;
}
Took about 74 seconds on my box using:
PHP 5.2.3-1ubuntu6 (cli) (built: Oct 4 2007 23:35:54)
Irrelevant to compare to his numbers but looks like it’s slow compared to the new ruby or python.
That’s an impressive speedup, but of course it just tests one little special case (a.k.a. a microbenchmark). Why don’t you go to the computer language shootout (http://shootout.alioth.debian.org/) and test all of their microbenchmarks. It would still be anecdotal evidence, but at least it would be more than just one microbenchmark.
Instead of doing all that benchmarking yourself, you should borrow someone else’s. Have a look on the Pentium-4 sandbox of the famous Computer Language Shootout: http://shootout.alioth.debian.org/
We’ve got a little set of test cases for various languages (including a new one we’ve built for internal use but are releasing as open source in case anyone else wants to play with it) and the results are improved but nowhere near as impressive as this thread implies.
lang cat grep hash loop proc sort wc
pl 0.35 0.36 0.63 0.11 0.30 2.03 1.03
py 0.37 1.08 0.46 0.18 0.17 1.83 0.48
rb 0.83 0.86 1.98 0.31 0.52 3.32 2.29
rb-snap 0.74 0.79 1.39 0.04 0.06 3.04 1.44
tcl 0.97 0.78 1.24 0.07 0.24 3.76 0.97
l 1.01 0.78 1.32 0.07 0.24 4.15 1.60
Here’s the langbench README:
langbench is a simplistic set of microbenchmarks designed to see how well
a scripting language performs at basic operations.
We (BitMover) are using it to benchmark our scripting language, you can
use it for whatever you like.
Copyright (c) 2007 by BitMover, Inc.
You may use for any purpose provided that if you use the “langbench” name
you report all results for all languages like so:
langbench version 0.5 results:
lang cat grep hash loop proc sort split
pl 0.85 0.85 1.38 0.24 0.68 4.72 5.13
py 0.81 2.97 1.03 0.34 0.40 4.37 1.56
rb 1.81 1.68 4.18 0.53 1.04 8.00 3.66
tcl 2.02 1.45 2.44 0.13 0.72 7.48 3.93
l 2.02 1.48 2.43 0.12 0.73 8.11 3.94
with the exception that you may leave off the L language until it is
widely distributed (defined as apt-get install l).
Test descriptions:
cat copy stdin to stdout
grep match a regular expression against stdin, print each match
hash use each line of stdin as a hash key, value is 1.
loop measure the cost of a loop
proc measure procedure call cost
sort sorts stdin to stdout
wc implements wc in a hand coded way
Input data is a million lines of code generated like this:
for i in 1 2 3 4 5 6 7 8 9 0
do cat tcl/generic/*.[ch]
done | head -1000000 > DATA
This file and tests are at http://www.bitmover.com/lm/langbench.shar
Ruby 1.9 doesn’t smoke Python away!
Antonio Cangiano compared execution time of recursive Fibonacci function written in Python and Ruby 1.9 and found that Ruby variant was almost 3 times as fast. It allowed him to write blog entry titled “Holy Shmoly, Ruby 1.9 smokes Python away!”. It’s time to show secret Python weapon – calculation of same Fibonacci numbers but in 1000 times faster than Antonio’s Ruby implementation.
http://www.mysoftparade.com/blog/ruby-19-doesnt-smoke-python-away/
@gnufied: Why isn’t it tail recursive? Looks like it to me. Just to make sure I wasn’t crazy I checked wikipedia and it says a tail recursive is when the last instruction is a recursive call, which those defs of fib fit.
Wowowow !!!
Really a beautiful Christmas present it seems !
By the way, I don’t really understand how you can improve a language to make it 15 times speeder on so simple script… 8|
Let’s take good news without too many questions 😉
Nevermind that 1.9 comes with a VM…
Isn’t it possible the code is compiled to bytecode and then run through the VM?
Bad choice of a benchmark, as the Fibonacci function can be cached. Using the Memoize module in Perl, I can perform the same calculation in 0.024 seconds on my Athlon64 3700+;
#!/usr/bin/perl
#
use strict;
use warnings;
use Memoize;
memoize( ‘fib’ );
for ( 0..36 ) {
print $_ . ‘ => ‘ . fib($_) . “\n”;
}
sub fib {
my $n = shift || 0;
return $n if ( $n < 2 );
return fib( $n-1 ) + fib( $n-2 );
}
@dataangel: +. The last call is +. fib(n – 1) + fib(n – 2) —> a = fib(n – 1); b = fib(n – 2); a + b
dataangel: it’s not tail-recursive, there’s an addition after the fib(n-1) and fib(n-2) calls.
Andrew: yes, the above code *is* run through the VM (ruby 1.9 doesn’t have an AST walker anymore).
I am not impressed by the results of this micro-benchmark (probably because I’m well-informed regarding Ruby 1.9); it’s always been well-known that 1.9 can be over 5 times faster than ruby 1.8 in such simplistic tests (in this case, the gains come mainly from the integer op optimizations introduced in YARV). The speedup is much more modest for more realistic tasks, and a few things are slower in 1.9.
IMO titles like “Ruby 1.9 smokes Python away!” inspire the wrong kind of reactions. (As tempting as they are, catchy headlines are best avoided if you care about the quality of the discussion more than about the number of visits.)
Hey friends. Here the benchmark is on *FUNCTION CALLS*, not on generating fibonacci numbers. *Of course* iterative or memoized algorithms are WAY faster. But in this version, to call fib() on every number from 0 to 35 means that we are measuring 78,176,300 function calls.
Nice that a couple of people mentioned the benchmarks game, looking at the recursive benchmark we’d see Ruby 1.9.0 doing 1.7x better than Python.
http://shootout.alioth.debian.org/gp4sandbox/benchmark.php?test=all&lang=yarv&lang2=python
Does anyone know how to increase the stack size in Ruby 1.9.0 – there’s an unhappy program –
http://shootout.alioth.debian.org/gp4sandbox/benchmark.php?test=recursive&lang=yarv&id=2#log
And for cold reality itself:
#include
unsigned long fib(int i) {
if (i == 0 || i == 1)
return 1;
return fib(i – 1) + fib(i – 2);
}
int main() {
int i = 0;
for (i = 0; i %ld\n”, i, fib(i));
return 0;
}
gcc -O6 -o fib fib.c
0.339 seconds.
It’s probably worth pointing out that this is the test that YARV (1.9) is really optimised for, and is not a fair representation of YARVs speed at processing general ruby apps.
Also, if you haven’t seen it already, check Charles’ post about JRuby and this particular benchmark:
http://headius.blogspot.com/2007/11/java-6-port-for-os-x-tiger-and-leopard.html
$0.02,
Enjoy.
That function can most certainly be made tail recursive. Here’s an Erlang version:
fib(N) -> fib(N, 1, 0).
fib(0, _, Result) -> Result;
fib(N, Next, Result) -> fib(N – 1, Next + Result, Next).
@she: I don’t think there’s that much conflict between the Ruby and Python communities. During this year’s RubyConf Keynote, Matz unbuttoned his shirt to show he was wearing a Python shirt underneath so there can’t be that much conflict:
http://www.flickr.com/photos/john_lam/1910968816/
Maybe there’s some friendly rivalry, but that only helps everyone improve. I’m a Ruby guy, but I think Python is a beautiful language.. most Ruby people I talk to think the same way.
On my system, JRuby finishes in about 23 seconds to Ruby 1.9’s 13 seconds. Not bad considering JRuby doesn’t have any integer math optimizations like Ruby 1.9 does. I think we can close the gap.
Ahem, your ruby program does *not* compute f(36) it only goes up to f(35). So I’m not sure Ruby 1.9 is much faster than Python; however it is impressive compared to Ruby 1.8.
Here are my results for another pair of languages:
Python 2.5 0m15.657s
GNU Smalltalk 2.95f 0m4.594s
For MacBook Pro, 2.2GHz, Leopard 10.5.1:
Ruby 1.8.6: 50s
Ruby1.9 edge: 12s
JRuby edge: 45s
JRuby edge -J-server: 20s
JRuby edge -J-server -J-Djruby.compile.frameless=true: 18s
Python 2.4.4: 30s
Python 2.4.4 + psyco: 1.8s (sic!)
Python 2.5.1: 54s
I like toreau pointing out that algorithmic consideration can have a huge effect, especially when folks are in the ‘yeah, well my obscure language of choice does it in N secs’ mode.
Ruby memoize version looks like the Perl version, minus some line noise and shifting and such cool things (although both have been my obscure language of choice at various times):
require “memoize”
def fib(n)
return n if(n < 2)
fib(n-1) + fib(n-2)
end
memoize(:fib)
# TODO: use fib, make benchmark claims
Nice to see the improvements in the Ruby interpreter and JRuby as a viable alternative. Yay, those guys.
Paolo wrote:
> Ahem, your ruby program does *not* compute f(36) it only goes up to f(35). So I’m not sure Ruby 1.9 is much faster than Python; however it is impressive compared to Ruby 1.8.
Paolo, both programs compute up to f(35). 🙂
I’m not sure how much slower a Core2Duo 2.2GHz is than a AMD X2 6000+, but on my system the Python version finishes in well under a second. So how can yours run for 31 seconds? That’s almost 1 second for every fib-number.
Done with Python 2.5.1 on 64bits Ubuntu.
I don’t have Ruby 1.9, but 1.8.6 runs about two minutes, that’s approx. 120 seconds. So Python (in this case) on my system is about 120 times faster than Ruby, how can yours only be 6 times faster? There’s something wrong with your system or your Python for sure.
SwitchBL8, my Python results were confirmed by people with similar hardware to mine. No one reported a significantly lower number than what I got. You have an excellent CPU there, but running the Python script in under a second seems like an unrealistic result. Are you sure you have just cut and pasted my snippet without altering anything? Iterative versions of the same script run in well under a second, this is true for both Ruby and Python, but the recursive one (without psyco or memoization) shouldn’t.
a faster algorithm,using python,0.6 sec.
>>> d={}
>>> def fib(n):
… if n==0 or n==1:
… return n
… if d.has_key(n):
… return d[n]
… else:
… temp = fib(n-1) + fib(n-2)
… d[n] = temp
… return temp
…
>>> for i in range(36):
… print “n=%d => %d” % (i, fib(i))
in my computer:
jdk1.6 52594/100= 0.52594s
delphi7 1m05s/100= 0.65s
VC6 1m11s/100= 0.71s
C#(.net2.0) 14s121/10= 1.4121s
python2.5 52s
ruby1.86 2m24s
[…] Announcing Publicity – A brand new language designed to smoke any other language out there. Some examples: […]
A very fast fib snippet in Ruby:
Fibonacci numbers in Ruby
http://snippets.dzone.com/posts/show/3562
@Antonio: I stand corrected. I used:
instead of yours. Results:
real 0m0.048s
user 0m0.012s
sys 0m0.016s
Using your script the results are about as slow as everybody elses:
real 0m24.502s
user 0m23.837s
sys 0m0.496s
So I guess you can create slow programs with Python too, didn’t know that.. 🙂
See Coderspiel
my results (core2duo @ 2.4 ghz)
antonio’s fibonacci test
ruby 1.8.6 => 82.8s
jruby 1.1b1 => 13.9s
ruby 1.9 => 8.7s
numerical test from http://numericalruby.com/2007/11/28/quick-numerical-benchmark-of-ruby-19/
ruby 1.8.6 => 111.8s
jruby 1.1b1 => 48.8s
ruby 1.9 => 44.5s
so ruby1.9 is about 2 – 10 times faster than ruby1.8
@luke: Later today I’ll publish “The Great Ruby Shootout”. It’s going to be fun. 🙂
🙁
in Java:
0=>0
1=>1
2=>1
3=>2
4=>3
5=>5
6=>8
7=>13
8=>21
9=>34
10=>55
11=>89
12=>144
13=>233
14=>377
15=>610
16=>987
17=>1597
18=>2584
19=>4181
20=>6765
21=>10946
22=>17711
23=>28657
24=>46368
25=>75025
26=>121393
27=>196418
28=>317811
29=>514229
30=>832040
31=>1346269
32=>2178309
33=>3524578
34=>5702887
35=>9227465
time=484ms
Psyco is an impressive piece of software, but it isn’t that useful for web applications. Why? Because you don’t care so much about speed increases as you do memory usage when it comes to web applications. In fact, the leading Python framework (Django) says in their documentation that it’s memory and not processing power that makes the difference. As soon as you start swapping, you’re toast.
As the Psyco webiste says, it uses a lot of memory. That means fewer server processes listening to requests. So, you might be cutting down some milliseconds off each request once that request gets heard, but you might also be dramatically increasing the time before an Apache process actually deals with a specific request.
In a world where memory is more the constraint than CPU, Psyco does more harm than good.
a trivial translation to ocaml
let rec fib n =
if n=0 || n=1 then n
else fib (n-1) + fib (n-2);;
for n = 0 to 35 do
Printf.printf “n=%d => %d\n” n (fib n);
done;;
runs 100 times faster than python
python 0m41.993s
ocaml 0m0.455s
So you have proven it takes 31.5 seconds to calculate 36 Fibonacci numbers in Python 2.5.1 if you use the dumbest possible algorithm (exponential complexity).
For calculating the first 36 Fibonacci numbers, I found this to be 6 orders of magnitude faster, i.e. giving a speedup by a factor of a million:
def fibo(n):
while 1:
try:
return fibo.seq[n]
except AttributeError:
fibo.seq = [0, 1, 1]
except IndexError:
fibo.seq.append( fibo.seq[-2] + fibo.seq[-1] )
A good choice of algorithm is far more important than language implementation.
Sturla, no one is disputing that. You can read my follow up here.
The point I am trying to make, is that real-world performance has very little to do with the speed of the Python or Ruby interpreter measured in micro-benchmarks. Where you could make your program run tree times faster by changing the VM from Python to Ruby, you could have made it a million times faster by changing the algorithm. Claims that “Python or Ruby is so slow”, and that “C++ or Java is so much faster”, have in 99% of the cases more to do with bad programming than the platform.
The thing that really matter is how Python or Ruby performs in the real world. And that depends mostly on the programmer. Google uses Python to run YouTube. NASA uses Python to process image data from Hubble. How slow can it be?
If you want to make Python look really bad, you can do as Peter Norvig and use Python lists for matrix multiplication (http://norvig.com/python-lisp.html). On the other hand, I could make Python with NumPy do wavelet transforms a lot faster than Matlab. Benchmarks just tend to tell lies.
I’m wondering about the memory usage. Currently i’m working with rails and found its serious memory leak problem, but django a kind of python’s framework doesn’t have such problem.
Not so sure whether your point of view is specific for recursive function or not?
If not that so, but just only fibonacci calculation,
I’ll wonder why you have to make things complicated?
I just simply code it as below:
def fn(n):
a = 0
b = 0
for i in range(1,n):
c = a + b
b = a
a = c
if a < 1: a += 1
print “n=%s %s” % (i,a)
return a
if __name__ == ‘__main__’: fn(36)
and the performance not so bad:
real 0m0.043s
user 0m0.024s
sys 0m0.012s
BTW, if you really really want to do it by recursive concept and strict with your code,
just apply psyco to your code and the result is supposed to be nearly 2.4s , and that’s mean, it’s even better than your ruby code which run on ruby 1.9.
I don’t know if there any JIT compilers in ruby?
But in real world task, don’t avoid to use any tools which offers you with better and easier way to done job.
And here’s hand-coded IBM Cell assembly:
fib: ENTRY
MOV A,0
MOV B,1
MOV C,0
MOV D,36 ;
fib2: SWP A,B
ADDR B,A,B
INC C
CMP C,D
JL fib2
end: RET B
Runs in 182 instructions if I’m counting correctly, which is exactly 0.00000001895833333333333269601445004656770088047323952196165919303894 seconds on a single CellEB 2 core.
wow that was cool, i hope this will make great influence to RoR too
Anything that gets a job done and done well requires to be complimented.
We have a long way to go. I have come a long way with python, I will try and go any distance with ruby too if it is simple enough, but go I will and fast.
If this rivalry does good great!!, if it is to stifle the other in the race for the ultimate good, we may fail to reach the ultimate destination.
Let us remember this.
You guys are great, and manking will always be thankful for the wonderful job you are doing, all of you EACH ONE of you.
I for one am thankful to be living in this world with all of you.
Spread Love Everywhere.
@Jan Rychter
that’s the whole point of using a language like python or ruby… there IS NO COMPILING NEEDED. no one is suggesting they are faster than compiled languages.
Ruby rocks.
can’t wait for 2.0 😉
Very glad to see so much valuable comments.
Unfortunately I do not see the huge improvement.
I have compiled ruby 1.8.6 and the ruby 1.9 (from ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.0-0.tar.gz), ran the same piece of code.
1.8.6 took 83 seconds, while 1.9 took 75 or so.
While it may have improved a little, I do not see any spectacular improvement.
Umm, ignore the above post 😛
Apparently the link created to the new ruby did not work as intended and I was testing the same version of ruby 😀
No wonder the results were rather similar
I didi some test about this python code in a Xeon running SuSE 10:
Python with no psyco:
48 seconds
Python with psyco:
1,6 seconds
Macruby: 0m11.020s
===== QUOTE =====
Reality check: C# 1.4 secs.
=== END QUOTE ===
I’m sorry, I can never resist these. Haskell translation (with whitespace-mangle-safe formatting):
main = mapM_ (putStrLn . join ” => “) . take 35 $ zip [1..] fibs where
join c (a, b) = show a ++ c ++ show b;
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
./fibs 0.00s user 0.00s system 84% cpu 0.004 total
Faster, simpler, shorter.
It’s funny that this post was written a year ago but there still isn’t any stable version of Ruby 1.9.
http://shootout.alioth.debian.org/u32q/benchmark.php?test=all&lang=ruby&lang2=python
Psyco vs YARV
http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=psyco&lang2=yarv
Interesting.
At least in this one instance, Jruby was faster than python [not psyco, mind you, which no one has yet written an equivalent for Ruby 🙂 ]
http://shootout.alioth.debian.org/u32q/benchmark.php?test=fannkuch&lang=all
So that’s good. In fact I think jruby is “almost as fast” as 1.9
@peke a “stable” 1.9 version is slated for February, I believe.
Cheers!
-=r
I’ve also done some comparison with similar results:
http://railstooge.blogspot.com/2009/01/ruby-vs-python-lame-benchmark.html
dataangel:
It’s not tail recursive, the last operation is the addition of the two calls to fib. A common enough mistake.
For the record, java 1.6 u10 does it in….
real 0m0.271s
Why all performance tests are all about recursive Fibonacci ..
building websites unfortunately include other processing operations and even more complicated not to mention file access, networking and string manipulations …
I would LOVE to see more about such benchmarks tests performed for realistic operations ..
Salem,
this is not a realistic benchmark; I program in, and love, both Ruby and Python. This post mostly pokes fun at Python programmers regarding the Ruby 1.9 improvements.
Realistic comparisons are very hard to do, and that’s why you’ll see very few of them floating around. For comparisons amongst Ruby implementations, I’ve started a Ruby Benchmark Suite that’s aimed at being somewhat realistic. Doing the same thing when it comes to comparing two different languages however, leaves much more room for error.
One of the technologies I’ve been examining lately which groovy / grails ..
Groovy as a scripting language is slower than ruby, However, taking in the whole stack (grails) it’s considered more scalable than Rails by all means, and this is what I really care about ..
In the company I’m working with now, we invested more than 2 years developing a social network service using rubyonrails, and the overall performance is killing us …
Yes I can create a blog in 20 minutes, but I spend more than 20 days just tweaking and struggling for little performance gain ..
Yet, no body even mentioned why it’s normal to have memory leak in our rails-based service so we have to restart the process every hour !!!
In Java:
Took: 22 sec
In Java it took around 0.4 sec while in groovy it took 22 seconds ..
I ran the fib test program. The result shows Ruby 1.9.1 on Windows took 50s instead of 12s:
ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32]: 120.469s
ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-mswin32]: 49.218s
How to explain this?
For those who misunderstood the purpose of the benchmark and suggested iterative, tail-recursive, or memoizing algorithms, I respectfully suggest that this is a better algorithm. It is extremely fast, is unlikely to have bugs, and did not take long to code:
# Glen’s benchmark algorithm:
ans = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181,
6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040,
1346269, 2178309, 3524578, 5702887, 9227465]
for x in ans:
print x
hoppinjohns: computers have different processor speeds and capabilities 😉
ruby test_fib.rb
62.25s user 8.15s system 99% cpu 1:10.85 total
python test_fib.py
23.90s user 0.00s system 99% cpu 23.912 total
booi test_fib.boo
1.12s user 0.02s system 99% cpu 1.141 total
(now prepare to be shocked)
booc test_fib.boo; time mono test_fib.exe
0.76s user 0.00s system 99% cpu 0.768 total
test_fib.boo:
What I want to say? NEVER try to compare interpreting languages in many-function-call-tasks. Compiled strong typed languages are much better in that case, coz no runtime-detection of types needed. And compiled languages does not need to be complex and heavy to learn. In example above I took “boo” – compileable (you can use booi – iterpreter-like version as well) strong-typed (but you can use non-strong-typed constructs – slower) language with python-like syntax.
As you can see in this traditional fibonacci task boo is 40 times faster than python. And difference will be much more in big apps.
So. Right language for right job.
Also. In this task boo+mono is faster than dump C app :):
@Vadim,
Multi-processor is the key, but there are many many implementations of stuff that will just lead you down an ultimately blind alley.
For one, I wouldn’t touch anything that furthers Microsoft’s interests.
I develop for my clients, not for sick greed.
Python 2.6.2 is faster and really faster with psyco:
On a Intel Core i7 940 (2.9 Ghz) :
16s for python 2.6.2 without psyco
0.9s with psyco !!!!!
lol ruby 1.9 kicks python ass.
[root@diego ~]# time ruby test.rb
n=0 => 0
n=1 => 1
n=2 => 1
…
n=34 => 5702887
n=35 => 9227465
real 0m15.056s
user 0m14.868s
sys 0m0.086s
[root@diego ~]# time python test.py
n=0 => 0
n=1 => 1
n=2 => 1
…
n=34 => 5702887
n=35 => 9227465
real 0m42.697s
user 0m42.107s
sys 0m0.165s
[root@diego ~]#
I develop to get paid.
A honest Haskel comparison (same algoritm), but it can be a lot faster (as shown by Twey).
fib :: Int -> Int
fib i | (i == 0) || (i == 1) = i
| otherwise = fib (i-1) + fib (i-2)
fibSeq :: [(Int, Int)]
fibSeq = [ (i, fib i) | i <- [0..36]]
Slim:Desktop jorrit$ ./fib
[(0,0),(1,1),(2,1),(3,2),(4,3),(5,5),(6,8),(7,13),(8,21),(9,34),(10,55),(11,89),(12,144),(13,233),(14,377),(15,610),(16,987),(17,1597),(18,2584),(19,4181),(20,6765),(21,10946),(22,17711),(23,28657),(24,46368),(25,75025),(26,121393),(27,196418),(28,317811),(29,514229),(30,832040),(31,1346269),(32,2178309),(33,3524578),(34,5702887),(35,9227465),(36,14930352)]
0.586306
Btw, that means 0.586306 seconds, what is more than 20 times faster than Ruby 1.9!
for me (windows)
ruby 1.9.1
16.2s
python 2.6
25s
ruby crystalized [1]
4.8s
Enjoy.
-r
[1] http://github.com/rdp/crystalizer
With jruby experiencing a speed up of about 200% thanks to invokedynamic in java 7.02 is time to rewrite the comparison.
http://blog.jruby.org/2011/12getting_started_with_jruby_and_java_7/
also in Hacker News:
http://news.ycombinator.com/item?id=3372816
Python on PyPy did this in 4.074s and in 17 secs on the same machine. Ruby did it in 10.5.
I’m happy to see Ruby getting some much needed optimization.
On my debian sid:
Ruby 1.8.7: 32.65s
Ruby 1.9.3: 5.85s
Python 2.7.3: 11.06s
Python 3.2: 11.89s
Haskell (no opt): 62.57s
Haskell (Compiled): 3.58s
So ruby 1.9 *is* fast.
Computer performance professor just showed us this, so I had to try it out with newer versions.
Slowest to fastest:
ruby 1.8: 0m26.671s
python 3.2: 0m8.979s
python 2.7: 0m7.676s
ruby 1.9.1: 0m5.610s
Lua 5.1.5: 0m5.074s
ubuntu 12.10, intel sandybridge i5-2500k quad-core 3.3GHz(i think), some fast ddr3 ram, all interpreters located on sata3 ssd.