This article will compare the latest incarnations of Ruby, with the latest in Python, Groovy, PHP, Lua, Perl and Java too, to have a comparison with a pre-compiled language. We will see, how scripting languages behave if applied to fractal geometry, more precisely an family Mandelbrot algorithm.
Browsing on the net, I found a comparison very interesting but a bit dated, dates back more than two years ago. Since then things have changed and I took advantage to make an update, not including all of those languages but only for more known. This is an opportunity to compare Ruby and Python versions even in their Java and. NET, an intention that I had since long time.
Using a fractal as a convenient benchmark plus: if an attempt to optimize not be successful if it has been the evidence and being drawn in real time, you can feel the speed. The fractal is drawn in ASCII also because the use of external libraries would have drugged the outcome.
*
*
*
*
*
***
*****
*****
***
*
*********
*************
***************
*********************
*********************
*******************
*******************
*******************
*******************
***********************
*******************
*******************
*********************
*******************
*******************
*****************
***************
*************
*********
*
***************
***********************
* ************************* *
*****************************
* ******************************* *
*********************************
***********************************
***************************************
*** ***************************************** ***
*************************************************
***********************************************
*********************************************
*********************************************
***********************************************
***********************************************
***************************************************
*************************************************
*************************************************
***************************************************
***************************************************
* *************************************************** *
***** *************************************************** *****
****** *************************************************** ******
******* *************************************************** *******
***********************************************************************
********* *************************************************** *********
****** *************************************************** ******
***** *************************************************** *****
***************************************************
***************************************************
***************************************************
***************************************************
*************************************************
*************************************************
***************************************************
***********************************************
***********************************************
*******************************************
*****************************************
*********************************************
**** ****************** ****************** ****
*** **************** **************** ***
* ************** ************** *
*********** ***********
** ***** ***** **
* * * *
This is the system for the test:
Dell Inspiron 9400, Centrino Duo, T7200 @ 2Ghz 4Mb Cache L1, Ram 2Gb @ 667Mhz
Windows XP pro SP3
Java 6 update 15
Microsoft .NET 3.5 SP1
These are the performance results obtained from an average of five runs, took after have executed some void attempts (I have not trusted the VM startup):
Language Time (in seconds) n times slower tha java _____________________________________________________________ Java 6 update 15 0,153 Lua 5.1.4 0,815 5x Php 5.3.0 2,083 14x Python 2.6.2 2,269 15x Python 3.1.1 1,566 10x Jython 2.5.0 2,850 19x Jruby 1.3.1 2,466 16x Groovy 1.6.3 6,491 42x Ruby 1.9.1 p129 2,688 18x Ruby 1.8.6 p368 6,863 45x Ruby 1.8.6 p111 9,709 63x IronRuby 0.9.0 6,038 39x IronPyhon 2.0.2 0,978 6x Perl 5.10.0 2,722 18x
This is the chart, of course lower values indicate better performance

These are the scripts used to generate the fractal, the originals was good, I have only done a few simple changes to run Python 3.1 or slightly improve the already excellent readability in Ruby and Lua.
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // by Erik Wrenholt import java.util.*; class Bench1 { static int BAILOUT = 16; static int MAX_ITERATIONS = 1000; private static int iterate(float x, float y) { float cr = y-0.5f; float ci = x; float zi = 0.0f; float zr = 0.0f; int i = 0; while (true) { i++; float temp = zr * zi; float zr2 = zr * zr; float zi2 = zi * zi; zr = zr2 - zi2 + cr; zi = temp + temp + ci; if (zi2 + zr2 > BAILOUT) return i; if (i > MAX_ITERATIONS) return 0; } } public static void main(String args[]) { Date d1 = new Date(); int x,y; for (y = -39; y < 39; y++) { System.out.print("n"); for (x = -39; x < 39; x++) { if (iterate(x/40.0f,y/40.0f) == 0) System.out.print("*"); else System.out.print(" "); } } Date d2 = new Date(); long diff = d2.getTime() - d1.getTime(); System.out.println("nJava Elapsed " + diff/1000.0f); } } |
Lua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | -- By Erik Wrenholt local BAILOUT = 16 local MAX_ITERATIONS = 1000 function iterate(x,y) local cr = y-0.5 local ci = x local zi = 0.0 local zr = 0.0 local i = 0 while 1 do i = i+1 local temp = zr * zi local zr2 = zr*zr local zi2 = zi*zi zr = zr2-zi2+cr zi = temp+temp+ci if (zi2+zr2 > BAILOUT) then return i end if (i > MAX_ITERATIONS) then return 0 end end end function bench1() local t = os.clock() for y = -39, 38 do for x = -39, 38 do if (iterate(x/40.0, y/40) == 0) then io.write("*") else io.write(" ") end end io.write("n") end io.write(string.format("Time Elapsed %.3fn", os.clock() - t)) end bench1() |
Php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <?php define("BAILOUT",16); define("MAX_ITERATIONS",1000); class Bench1 { function Bench1() { $d1 = microtime(1); for ($y = -39; $y < 39; $y++) { echo("n"); for ($x = -39; $x < 39; $x++) { if ($this->iterate($x/40.0,$y/40.0) == 0) echo("*"); else echo(" "); } } $d2 = microtime(1); $diff = $d2 - $d1; printf("nPHP Elapsed %0.3f", $diff); } function iterate($x,$y) { $cr = $y-0.5; $ci = $x; $zi = 0.0; $zr = 0.0; $i = 0; while (true) { $i++; $temp = $zr * $zi; $zr2 = $zr * $zr; $zi2 = $zi * $zi; $zr = $zr2 - $zi2 + $cr; $zi = $temp + $temp + $ci; if ($zi2 + $zr2 > BAILOUT) return $i; if ($i > MAX_ITERATIONS) return 0; } } } new Bench1(); ?> |
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | import sys, time stdout = sys.stdout BAILOUT = 16 MAX_ITERATIONS = 1000 class Bench1: def __init__(self): print ('Rendering...') for y in range(-39, 39): stdout.write('n') for x in range(-39, 39): i = self.start(x/40.0, y/40.0) if i == 0: stdout.write('*') else: stdout.write(' ') def start(self, x, y): cr = y - 0.5 ci = x zi = zr = 0.0 i = 0 while True: i += 1 temp = zr * zi zr2 = zr * zr zi2 = zi * zi zr = zr2 - zi2 + cr zi = temp + temp + ci if zi2 + zr2 > BAILOUT: return i if i > MAX_ITERATIONS: return 0 t = time.time() Bench1() print ('nPython Elapsed %.3f' % (time.time() - t)) |
Groovy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | //Created By Marco Mastrodonato 22/09/2009 class Bench1{ public int BAILOUT = 16 public int MAX_ITERATIONS = 1000 def Bench1(){ println("Rendering...") for (y in -39..39){ println("") for (x in -39..39){ if (iterate(x/40.0, y/40.0) == 0){ print("*") } else { print(" ") } } } } def iterate(x,y){ float cr = y-0.5 float ci = x float zi = 0.0 float zr = 0.0 def i = 0 while(1){ i += 1 float temp = zr * zi float zr2 = zr * zr float zi2 = zi * zi zr = zr2 - zi2 + cr zi = temp + temp + ci if (zi2 + zr2 > BAILOUT){ return i } if (i > MAX_ITERATIONS){ return 0 } } } } time1 = new Date().time new Bench1() time2 = new Date().time float elapsed = (time2 - time1)/1000 println("nGroovy Elapsed ${elapsed}") |
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | BAILOUT = 16 MAX_ITERATIONS = 1000 class Bench1 def initialize puts "Rendering..." for y in -39..39 print "n" for x in -39..39 i = iterate x/40.0, y/40.0 if i == 0 then print "*" else print " " end end end end def iterate(x,y) cr = y-0.5 ci = x zi = zr = 0.0 i = 0 while true i += 1 temp = zr * zi zr2 = zr * zr zi2 = zi * zi zr = zr2 - zi2 + cr zi = temp + temp + ci return i if zi2 + zr2 > BAILOUT return 0 if i > MAX_ITERATIONS end end end time = Time.now Bench1.new puts "nRuby Elapsed %.3f" % (Time.now - time) |
Perl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | # Ported from C to Perl by Anders Bergh <anders1@gmail.com> $BAILOUT=16; $MAX_ITERATIONS=1000; $begin = time(); sub mandelbrot { local $x = $_[0]; local $y = $_[1]; local $cr = $y - 0.5; local $ci = $x; local $zi = 0.0; local $zr = 0.0; local $i = 0; while (1) { $i = $i + 1; local $temp = $zr * $zi; local $zr2 = $zr * $zr; local $zi2 = $zi * $zi; $zr = $zr2 - $zi2 + $cr; $zi = $temp + $temp + $ci; if ($zi2 + $zr2 > $BAILOUT) { return $i; } if ($i > $MAX_ITERATIONS) { return 0; } } } for ($y = -39; $y < 39; $y++) { print("n"); for ($x = -39; $x < 39; $x++) { $i = mandelbrot($x/40.0, $y/40.0); if ($i == 0) { print("*"); } else { print(" "); } } } print("n"); $end = time() - $begin; printf ("Perl Elapsed %.3fn",$end); |
Comments:
The speed of Lua isn’t a news: only 5 times slower than compiled Java code, the best result. Its simplicity is its strength, maybe that’s what makes it so fast? It was adopted by Blizzard in the videogame “World of Warcraft” and if they did so, with no doubt, there is a reason. It is not object-oriented, does not natively support objects even if there is a project LOOP that extends this programming model.
PHP and Perl does not need comments.
Among the C version of Ruby and Python is clearly faster the second. The fair comparison would be the Rb1.8.6 with Py2.6.2 and Rb1.9.1 with Py3.1.1.
The challenge between the versions that uses the Java VM: Groovy, Jython and JRuby, sees the last as the winner. Groovy is far behind as performance in this test but the biggest question I have is: who is it for? As syntax is not bad but, imho, Ruby is even more fluent and then have that rake that is so convenient for many things.
The challenge between the .NET versions sees IronPython incredibly forward! But what they put in, the dynamite? It will be very interesting to examine the new ASP.NET MVC framework recently arrived at version 1 and that will be included in the framework. Net 4, there are projects for both IronRuby IronPython.
If this article was interesting, perhaps you can find something else through the advertisements of my sponsor, is in the right column, thanks!
Bye!





English
Italiano