Meditations on programming, startups, and technology
New Relic

Holy Shmoly, Ruby 1.9 smokes Python away!

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!


If you enjoyed this post, then make sure you subscribe to my Newsletter and/or Feed.

receive my posts by email

104 Responses to “Holy Shmoly, Ruby 1.9 smokes Python away!”

  1. Bruno says:

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

  2. karim says:

    What about psyco? have you tried it?
    http://psyco.sourceforge.net/

  3. vuk says:

    There are lies, damn lies and Benchmarks… ;-)

  4. Christian says:

    Does Ruby 1.9 optimize tail recursive calls? That’s great. Can you post a link where this is documented?

  5. xtian says:

    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?

  6. gnufied says:

    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….

  7. Oliver says:

    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.

  8. [...] 28, 2007 in nout??iTags: python, ruby19 Antonio Cangiano a f?cut un mic test cu Python 2.5.1 ?i Ruby 1.9, rulând o func?ie care calculeaz? ?irul lui Fibonacci [...]

  9. Greg Graham says:

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

  10. 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.

  11. she says:

    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!

  12. I wholeheartedly agree with you Andrew.

  13. Chris Khoo says:

    “Mmmm.. yes fascinating,” he mumbles as he switches back to his vim window editing C source.

  14. Leonardo says:

    It is really goo to hear that as one of my main concerns today is ruby’s speed!

    Thanks man!

  15. foo says:

    Wow. I’m impressed by how much Ruby manages to uglify simple code snippets.

  16. arman says:

    wow…Ruby is getting faster compared to python. But it doesnt mean, ruby is more powerful than python. anyway, i still love php. ;-)

  17. Python has very slow recursion performance

    Just today I read a post from Antonio showing how big of an improvement Ruby …

  18. dyork says:

    Reality check: C# 1.4 secs.

  19. That’s cool thanks for sharing, i hope to do some benchamarks between 1.8 and 1.9

  20. Ola Bini says:

    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.

  21. 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

  22. pp says:

    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.

  23. 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?

  24. Anurag says:

    Heh, day by day, python vs. ruby is becoming more like vi/emacs wars!

  25. Bob Holness says:

    This just goes to prove how crap Python is. ;)

    (BTW, what is Python?)

  26. Ech, Python 2.4.4 + psyco gives: 2.5 sek :-D

  27. tim says:

    On my PC, python takes 20 secs without psyco. With psyco, only 1.5 secs!

  28. Jan Rychter says:

    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.

  29. mkaatman says:

    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.

  30. 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.

  31. sapphirecat says:

    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/

  32. Larry McVoy says:

    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

  33. [...] real point to take from Antonio Cangiano’s article, Holy Shmoly, Ruby 1.9 smokes Python away!, is not that Ruby 1.9 runs circles around Python, but that Ruby 1.9’s performance appears to [...]

  34. 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/

  35. dataangel says:

    @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.

  36. Sobe says:

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

  37. Andrew says:

    Nevermind that 1.9 comes with a VM…

    Isn’t it possible the code is compiled to bytecode and then run through the VM?

  38. toreau says:

    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 );
    }

  39. Logan says:

    @dataangel: +. The last call is +. fib(n – 1) + fib(n – 2) —> a = fib(n – 1); b = fib(n – 2); a + b

  40. mfp says:

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

  41. pp says:

    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.

  42. Isaac Gouy says:

    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

  43. Matthew says:

    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.

  44. raggi says:

    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.

  45. bascule says:

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

  46. Dan says:

    @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.

  47. 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.

  48. [...] têm acontecido na minha universidade (mais uma vez), achei relevante o post que ele fez sobre a performance do Ruby 1.9. Aconselho a leitura. Fica, como resumo, os resultados obtido comparando a função de fibbonacci [...]

  49. [...] Holy Shmoly, Ruby 1.9 smokes Python away! [...]

  50. 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

  51. [...] following a series of posts that started with this one, moved to this one and, so far, has reached this one. To save you the bother of reading these the [...]

  52. 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

  53. ARJ says:

    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.

  54. [...] the expression ‘Holy Schmoly’ before. Now in two days i’ve read it twice, and both times in the context of computing languages performance. Two times too often, if you ask me. But [...]

  55. 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). :)

  56. SwitchBL8 says:

    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.

  57. 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.

  58. ictboy says:

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

  59. [...] Haskell, Ruby Smackdown November 30, 2007 Antonio Cangiano writes about how the new and improved Ruby 1.9 is actually faster than Python for a fibonacci [...]

  60. vicalloy says:

    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

  61. [...] Announcing Publicity – A brand new language designed to smoke any other language out there. Some examples: [...]

  62. [...] My post about Ruby 1.9’s impressive improvement over Ruby 1.8.6 created quite an echo within the developer community. Sure, the headline was an attention grabber, just like this one is :-P, but in a matter of a few hours, there were all sorts of blog entries with variants in many languages, more than 200 comments on Reddit, and fifty comments on my own blog. There were however, also a few misconceptions. It was great though because such a simple post generated a lot of discussion amongst developers, with some insightful arguments taking place – and besides it almost created a new meme with the whole “holy shomly” thing. Fun as that certainly was, let’s try to summarize and clarify a few points. [...]

  63. niko says:

    A very fast fib snippet in Ruby:

    Fibonacci numbers in Ruby

    http://snippets.dzone.com/posts/show/3562

  64. [...] reading this article comparing the new Ruby 1.9 to it’s older version and Python, I though it would be interesting [...]

  65. Microbenchmark: Ruby 1.9.0 contro tutti (… non proprio…)

    Il rilascio di Ruby 1.9 è previsto intorno a Natale e con il passare dei giorni la curiosità dei rubyisti si fa sempre più intensa. Stuzzicato da un microbenchmark pubblicato da Antonio Cangiano sul suo blog in cui ha messo a confronto l…

  66. SwitchBL8 says:

    @Antonio: I stand corrected. I used:

    #!/usr/bin/env python
    
    def fib(n):
      return fib_r(0, 1, n)
    
    def fib_r(cur, next, rem):
      if rem == 0:
        return cur
      else:
        return fib_r(next, cur + next, rem - 1)
    
    for i in range(36):
        print "n=%d => %d" % (i, fib(i))
    

    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

  67. luke says:

    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

  68. @luke: Later today I’ll publish “The Great Ruby Shootout”. It’s going to be fun. :)

  69. [...] Update Holy Shmoly, Ruby 1.9 smokes Python away! Ruby 1.9 doesn’t smoke Python away!  Quick numerical benchmark of Ruby 1.9 [...]

  70. lvcha says:

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

  71. [...] are being generated to make “your religion language” look good against others (usually by misusing the language you want to bash). There is a semantic difference between discussing a language itself, it’s syntax, it’s standard [...]

  72. Adam says:

    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.

  73. [...] Ruby 1.8.6: 158.869s Python 2.5.1: 31.507s Ruby 1.9.0: 11.934s [...]

  74. aaa says:

    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

  75. Sturla Molden says:

    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.

  76. Sturla, no one is disputing that. You can read my follow up here.

  77. Sturla Molden says:

    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.

  78. ShiningRay says:

    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.

  79. BLeAm says:

    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.

  80. [...] have been guiding the implementation of 1.9, which above all should be much faster than 1.8 (and more competitive with other languages). More detailed changes here.Also, in case you didn’t hear, Rails 2.0 was released last month. [...]

  81. HYPER says:

    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.

  82. adit says:

    wow that was cool, i hope this will make great influence to RoR too

  83. Satish says:

    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.

  84. [...] with the new Parser Ruby is 3 times as fast as Python. [...]

  85. JMC says:

    @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.

  86. [...] There’s hope though. Apparently, function calling should be a lot faster in Ruby 1.9 [...]

  87. Diego Viola says:

    Ruby rocks.

    can’t wait for 2.0 ;-)

  88. Hodak says:

    Very glad to see so much valuable comments.

  89. bogdan says:

    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.

  90. bogdan says:

    Umm, ignore the above post :P
    Apparently the link created to the new ruby did not work as intended and I was testing the same version of ruby :D
    No wonder the results were rather similar

  91. [...] for more microbenchmarks! Someone just pointed me out to this post which describes another fibonacci shootout. This one gives the brand new Ruby 1.9 VM a test drive. [...]

  92. Jorge says:

    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

  93. [...] planned support for tail call optimization tonight, and found a Weblog post talking about how bare recursion is much faster in Ruby 1.9 than Python 2.5. This is not even tail recursive code in the example. Discussion in comments there suggests that [...]

  94. Linan says:

    Macruby: 0m11.020s

  95. Twey says:

    ===== 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.

  96. peke says:

    It’s funny that this post was written a year ago but there still isn’t any stable version of Ruby 1.9.

  97. attrappe says:

    Psyco vs YARV

    http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=psyco&lang2=yarv

    memory usage
         Psyco = YARV
    
    Faster
         Psyco > YARV
    
  98. Roger says:

    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

  99. [...] I suppose -?- that the interpreters I talk about below are coded in C)… I’ve found on the page http://antoniocangiano.com/2007/11/2…s-python-away/ a discussion about the performance differences between several languages (Ruby, Perl, Python…) to [...]

  100. [...] 6.8 smokes Python and Ruby away! And you can parallelise it for free November 29, 2007 Antonio Cangiano writes about how Ruby 1.9 has improved in various ways, so that the naive fibonacci algorithm is [...]

  101. Justin says:

    dataangel:

    It’s not tail recursive, the last operation is the addition of the two calls to fib. A common enough mistake.

  102. [...] nauja, stabili ruby versija. Pakeitim? yra labai daug, iš j? išskir?iau greitaveik?, bei [...]

  103. [...] Ruby è infatti notevolmente più veloce rispetto alla precedente come dimostrò uno tra i primi test pubblicati da Antonio [...]

  104. obnoxiousguy says:

    For the record, java 1.6 u10 does it in….
    real 0m0.271s

  105. Salem says:

    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 ..

  106. 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.

  107. Salem says:

    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 !!!

  108. Salem says:

    In Java:

    import java.util.Date;
    
    public class test3 {
        public static void main(String[] args)  {
            System.out.println ("hello");
    
    
            long s = new Date().getTime();
            for(int i=1; i
      println "n=${i} => ${fib(i)}"
    }
    
    e = new Date()
    
    println e.getTime() - s.getTime()
    

    Took: 22 sec

  109. Salem says:

    In Java it took around 0.4 sec while in groovy it took 22 seconds ..

  110. hoppinjohns says:

    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?

  111. glen worstell says:

    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

  112. Donnie says:

    hoppinjohns: computers have different processor speeds and capabilities ;)

  113. [...] reading this article comparing the new Ruby 1.9 to it’s older version and Python, I thought it would be [...]

  114. Vadim Fint says:

    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:

    def fib(n as int) as int:
       if n == 0 or n == 1:
          return n
       else:
          return fib(n-1) + fib(n-2)
    
    for i in range(36):
        res = fib(i)
        print "n=${i} => ${res}"
    

    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.

  115. Vadim Fint says:

    Also. In this task boo+mono is faster than dump C app :):

    int fib(int n) {
            if (n == 0 || n == 1) {
                    return n;
            } else {
                    return fib(n-1) + fib(n-2);
            }
    }
    
    int main(char* argv, int argc) {
        int i;
            for (i = 0; i  %d\n", i, fib(i));
            }
    }
    
    ./test_fib
    0.95s user 0.00s system 99% cpu 0.957 total
    
  116. Mark says:

    @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.

  117. Eric says:

    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 !!!!!

  118. Diego Viola says:

    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 ~]#

  119. Real World says:

    I develop to get paid.

  120. Jorrit Posthuma says:

    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

  121. Jorrit Posthuma says:

    Btw, that means 0.586306 seconds, what is more than 20 times faster than Ruby 1.9!

  122. roger says:

    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

  123. peddro vallle says:

    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

  124. michael says:

    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.

  125. Rohan Jain says:

    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.

    • Johan Nestaas says:

      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.

Leave a Reply

I sincerely welcome and appreciate your comments, whether in agreement or dissenting with my article. However, trolling will not be tolerated. Comments are automatically closed 15 days after the publication of each article.

Current ye@r *

Copyright © 2005-2014 Antonio Cangiano. All rights reserved.