RSS
 

Posts Tagged ‘Python’

Files di grandi dimensioni su Windows Server 2008 R2 64Bit

21 Apr

Nel precedente articolo ho esaminato la semplice lettura e scrittura di tre files con dimensioni da 330Mb a 2,6Gb, su un normalissimo PC con Windows XP. Ora vediamo cosa cambia su un server virtuale, sistema produttivo che coinvolge un numero di aziende sempre più ampio.

I linguaggi in esame sono i seguenti:

Ruby 1.8.6 p383 (2009-08-04) [i386-mingw32]
Ruby 1.8.7 p334 (2011-02-18) [i386-mingw32]
Ruby 1.9.2 p180 (2011-02-18) [i386-mingw32]
jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_23) [Windows Server 2008 R2-amd64-java]
IronRuby 1.1.3.0 (ruby-1.9.2) on .NET 4.0.30319.225
Python 2.7.1 32bit
Python 2.7.1 64bit
Python 3.2.0 32bit
Python 3.2.0 64bit
Php 5.3.6 vc9 unsafe thread
Lua 5.1.4 40
C# 32bit on .NET 2.0.50727.4927
C# 64bit on .NET 2.0.50727.4927
C# 32bit on .NET 4.0.30319.1
C# 64bit on .NET 4.0.30319.1

Solo python fornisce pacchetti di installazione x64 e ne ho approfittato per confrontarli con le versioni a 32 bit. Probabilmente le differenze si noteranno con operazioni matematiche rispetto la sezione IO ma questo apre la strada alla prossima comparazione.

La versione di ruby 1.8.6 è una mingw32 e non mswin32 come nel precedente test. IronRuby invece è l’ultima 1.1.3 che abbraccia il supporto a ruby 1.9.2 e non 1.8.6 come la versione del precedente test con cui, comunque, condivide lo stesso framework .net e la stessa sezione IO.
Questa volta ho anche aggiunto C# nella comparazione, ho compilato quattro versioni differenziando per piattaforma, x86 e x64, ed anche per framework, 3.5 e 4. Il framework .net 3.5 utilizza lo stesso CLR del 2.0.

Una nota di merito a IronRuby, il primo della classe che è persino davanti a C#, linguaggio compilato e con cui condivide molto. E’ vero che questo test non richiede potenza computazionale particolarmente elevata ma è certamente un risultato curioso.

Un riepilogo anche sul consumo della memoria:

Lua 5.1.4 0,7mb
Php 5.3.6 2,2mb
Python 2.7.1 32bit 2,5mb
Python 3.2.0 32bit 3,7mb
Python 2.7.1 64bit 4mb
Python 3.2.0 64bit 5,5mb
Ruby 1.9.2p180 4-6mb
Ruby 1.8.6p383 4-9mb
Ruby 1.8.7p334 4-9mb
C# 32bit on .NET 2.0.50727.4927 7mb
C# 32bit on .NET 4.0.30319.1 7mb
C# 64bit on .NET 2.0.50727.4927 9mb
C# 64bit on .NET 4.0.30319.1 9mb
IronRuby 1.1.3.0 on .NET 4.0.30319.225 11mb
jruby 1.6.1 (JVM 64-Bit Server 1.6.0_23) jruby 1mb + java 200mb

Questo è il codice C# che ho compilato con Visual Studio 2010:

using System;
using System.IO;
 
namespace Split
{
    class Program
    {
 
        /// <summary>
        /// To split a file into n output files
        /// </summary>
        /// <param name="args">Filename and records number to split</param>
        static void Main(string[] args)
        {
            string strInput = args[0];
            string strOutput = "out_{0:000}.txt";
            Int32 nrec_to_split = Convert.ToInt32(args[1]);
 
            DateTime t1 = DateTime.Now;
            Console.WriteLine("C# {1} Started at {0:R}, please wait...", t1, System.Environment.Version);
 
 
            StreamReader sr;
            StreamWriter sw = null;
            sr = new StreamReader(strInput);
            Int16 nsplit = 0;
            Int64 nrec = 0;
            while (sr.Peek() >= 0)
            {
                if (nrec % nrec_to_split == 0)
                {
                    ++nsplit;
                    if (sw != null) sw.Close();
                    sw = new StreamWriter(String.Format(strOutput, nsplit));
                }
                sw.WriteLine(sr.ReadLine());
                ++nrec;
            }
 
            Console.WriteLine("Ended at {0:R}, please wait...", DateTime.Now);
            Console.WriteLine("Elapsed time {0}", DateTime.Now - t1);
        }
 
    }
}
 
Comments Off

Posted in IronRuby .NET, JRuby, Prestazioni, Python, Ruby

 

Ruby, Python, Php e Lua in comparazione con files di grandi dimensioni

19 Apr

Vediamo come si comporta la sezione IO di alcuni tra i più popolari linguaggi script. L’esercizio consiste nel leggere sequenzialmente un grosso file di input e dividerlo in files più piccoli, in termini pratici, splittarlo.

I linguaggi in esame sono:
Ruby 1.8.6 p287 (2008-08-11) [i386-mswin32]
Ruby 1.8.7 p334 (2011-02-18) [i386-mingw32]
Ruby 1.9.2 p180 (2011-02-18) [i386-mingw32]
jruby 1.5.1 (ruby 1.8.7 patch 249) (Java HotSpot(TM) Client VM 1.6.0_14) [x86-java]
jruby 1.5.1 (ruby 1.8.7 patch 249) (Java HotSpot(TM) Client VM 1.6.0_24) [x86-java]
jruby 1.6.1 (ruby-1.8.7-p330) (Java HotSpot(TM) Client VM 1.6.0_24) [Windows XP-x86-java]
IronRuby 1.1.0.0 on .NET 4.0.30319.225
Python 2.6.2
Python 2.7.1
Python 3.2.0
Php 5.3.6 vc9 unsafe thread
Lua 5.1.4 40

Iniziamo col creare i tre files di input necessari per il test:
ruby new.rb input1.txt 185000 1799 => 330Mb
ruby new.rb input2.txt 500000 1799 => 880Mb
ruby new.rb input3.txt 1500000 1799 => 2,6Gb

Il test l’ho eseguito su un PC con cpu Intel E7300 Core2 Duo 2,66Ghz Ram 3,25Gb con Windows XP Professional 32bit, Hard Disk ST3250310AS Barracuda 7200.10 SATA 3.0Gb/s da 250Gb.

Prossimamente lo eseguirò anche su un Server Windows 2008 R2 64bit su VMWare Xeon X7460 Dual Core a 2,66Ghz e 2Gb di ram con dischi SCSI.

Prima e dopo aver creato i tre files di input ho deframmentato il disco. Se i tempi sono incostanti significa che il disco deve essere deframmentato o c’è qualcosa che rallenta il sistema come ad esempio l’antivirus che deve essere disabilitato.

Per ogni file ho eseguito sei elaborazioni e considerando le scarse prestazioni IO del sistema, ho scartato le tre peggiori. Naturalmente, prima di ogni test ho eliminato i files di output.

I grafici parlano da soli.
L’unico commento che posso fare riguarda la versione 1.9.2 di ruby che ha evidenti problemi di IO e questi risultati non sono in linea con le performance generali di questo linguaggio che, come ho potuto rilevare da altri precedenti test, sono invece molto buone.

Questi sono gli script che ho scritto per l’occasione:

# Written by Marco Mastrodonato on 19/04/2011
# Script to split a file into n output files
# Example:
# ruby split.rb par1 par2
# par1 => name [default => input1.txt]
# par2 => record number that determines the number of output files [default => 1650]
 
strinput = ARGV[0] || 'input1.txt'
nrec_to_split = ARGV[1] ? ARGV[1].to_i : 1650
 
unless File.exists? strinput
	puts "File #{strinput} doesn't exists!" 
	exit 1
end
 
stroutput = "out_%03d.txt"
 
t1= Time.now
puts "Ruby #{RUBY_VERSION} #{strinput} started at #{t1}, wait please..."
 
File.open(strinput, "r") do |f|
	nsplit = 0
	nrec = 0
	fileoutput = nil
 
	while line = f.gets
		if nrec % nrec_to_split == 0
			nsplit += 1
			fileoutput.close if fileoutput
			fileoutput = File.open(stroutput % nsplit, 'w')
		end
		fileoutput.write line
		nrec += 1
	end
 
	fileoutput.close if fileoutput
end
 
puts "Ended at #{Time.now}"
puts "Elapsed time #{Time.now - t1}"
exit 0
# Written by Marco Mastrodonato on 19/04/2011
# Script to split a file into n output files
# Example:
# python split.py par1 par2
# par1 => name [default => input1.txt]
# par2 => record number that determines the number of output files [default => 1650]
 
from time import time, gmtime, strftime
import sys
 
try:
	strinput = sys.argv[1]
except:
	strinput = 'input1.txt'
 
stroutput = "out_%03d.txt"
 
try:
	nrec_to_split = int(sys.argv[2])
except:
	nrec_to_split = 1650
 
t1 = time()
print(sys.version)
print(strftime("Started at %a, %d %b %Y %H:%M:%S +0000, wait please...", gmtime()))
 
nrec = 0
nsplit = 0
 
fileinput = open(strinput, "r")
for line in fileinput:
	if nrec % nrec_to_split == 0:
		try:
			fileoutput.close()
		except NameError:
			fileoutput = None
		nsplit += 1
		fileoutput = open(stroutput %nsplit , "w")
	fileoutput.write(line)
	nrec += 1    
fileoutput.close()
fileinput.close()
 
print(strftime("Ended at %a, %d %b %Y %H:%M:%S +0000", gmtime()))
print("Elapsed time %f" %(time() - t1))
<?php
// Written by Marco Mastrodonato on 19/04/2011
// Script to split a file into n output files
// Example:
// php split.php par1 par2
// par1 => name [default => input1.txt]
// par2 => record number that determines the number of output files [default => 1650]
 
$strinput = isset($argv[1]) ? $argv[1] : 'input1.txt';
$nrec_to_split = isset($argv[2]) ? $argv[2] : 1650;
$stroutput = 'out_%03d.txt';
 
$t1 = microtime_float();
echo "Php ".phpversion()." started at ".date('D, d M Y H:i:s T').", wait please...\n";
 
$nsplit = 0;
$nrec = 0;
$fileinput=fopen($strinput,"r");
 
while(!feof($fileinput)) {
	if ($nrec % $nrec_to_split == 0) {
		++$nsplit;
		if (isset($fileoutput)) fclose($fileoutput);
		$fileoutput = fopen(sprintf($stroutput, $nsplit), 'w');
	}
	$buffer = fgets($fileinput);
	fwrite($fileoutput, $buffer);
	++$nrec;
}
 
fclose ($fileinput);
 
echo "Ended at ".date('D, d M Y H:i:s T')."\n"; 
echo "Elapsed time ".(microtime_float() - $t1)."\n";
 
 
function microtime_float() {
	list($usec, $sec) = explode(" ", microtime());
	return ((float)$usec + (float)$sec);
}
 
?>
--[[
Written by Marco Mastrodonato on 19/04/2011
Script to split a file into n output files
Example:
lua split.lua par1 par2
par1 => name [default => input1.txt]
par2 => record number that determines the number of output files [default => 1650]
--]]
strinput = arg and arg[1] or "input1.txt"
stroutput = "out_%03d.txt"
nrec_to_split = arg and arg[2] and tonumber(arg[2]) or 1650
 
local t1 = os.clock()
print(_VERSION .. " started at " .. os.date("%a, %d %b %Y %H:%M:%S +0000"))
 
nsplit = 0
nrec = 0
for line in io.lines(strinput) do
  if nrec % nrec_to_split == 0 then
    if fileOut ~= nil then io.close(fileOut) end
    nsplit = nsplit + 1
    fileOut = io.open(string.format(stroutput, nsplit) , 'w')
  end
  fileOut:write (line .. '\n')
  nrec = nrec + 1
end
 
io.close(fileOut)
 
print("Ended at " .. os.date("%a, %d %b %Y %H:%M:%S +0000"))
print(string.format("Elapsed time: %.2f\n", os.clock() - t1))

Per creare i files ho usato questo semplice script ruby:

# Example:
# ruby new.rb [NOME] [LINES] [RECORD SIZE]
 
stroutput = ARGV[0] || 'input1.txt'
num = ARGV[1] ? ARGV[1].to_i : 185000
size = ARGV[2] ? ARGV[2].to_i : 1799
 
if File.exists? stroutput
	puts "File #{stroutput} already exists!" 
	exit 1
end
 
t1= Time.now
puts "Ruby #{RUBY_VERSION} #{stroutput} started at #{t1}, wait please..."
 
line = "*" * size
 
File.open(stroutput, "w") do |f|
	num.times do
		f.puts line
	end
end
 
puts "Ended at #{Time.now}"
puts "Elapsed time #{Time.now - t1}"
exit 0
 

Ruby vs Python vs Windows vs Linux

05 Mar

Nel precedente articolo, ho esaminato le prestazioni di alcuni interpreti ruby e python, su un sistema windows xp. Questa volta, ho eseguito gli stessi script sotto linux: distribuzione ubuntu 9.10 2.6.31-20-generic. Le versioni APT sono state installate tramite gestore di pacchetti, le RVM invece, tramite il Ruby Version Manager e compilate dai sorgenti.

Versione Compilatore/Sistema/VM Secondi
JRuby 1.4.0 APT Java HotSpot(TM) 64-Bit Server VM 1.6.0_16) [amd64-java] 6,1
JRuby 1.4.0 RVM Java HotSpot(TM) 64-Bit Server VM 1.6.0_16) [amd64-java] 6,2
Ruby 1.9.2 preview1 RVM x86_64-linux 6,5
JRuby 1.4.0 Windows Client VM 1.6.0_15 [x86-java] 6,9
Python 2.6.4 Windows 7,5
Ruby 1.9.1 p129 i386-mingw32 8,1
Python 2.6.4 APT x86_64-linux 8,7
Ruby 1.9.1 p378 RVM x86_64-linux 8,7
Ruby 1.9.1 p243 RVM x86_64-linux 8,8
Python 3.1.1 Windows 9,0
Ruby 1.9.1 p243 APT x86_64-linux 9,3
Ruby 1.9.1 p243 i386-mingw32 9,6
Ruby 1.8.7 p249 RVM x86_64-linux 12,2
IronRuby 0.9.3.0 Windows .NET 2.0.0.0 18,9
Ruby 1.9.1 p376 i386-mswin32 20,8
Ruby 1.8.7 p174 APT x86_64-linux 23,0
Ruby 1.8.6 p368 i386-mingw32 23,3
Ruby 1.8.7 p249 i386-mingw32 23,9
IronPython 2.6 Windows .NET 2.0.0.0 256,5
Jython 2.5.1 Windows Client VM 1.6.0_15 [x86-java] Timeout

Win vs Linux

Win vs Linux

 

Ruby vs Ruby vs Python vs Python

24 Jan

Un altro benchmark che mette a confronto alcune recenti versioni di ruby con gli ultimi rilasci di python. Due semplici script per confrontare sintassi e prestazioni di questi moderni linguaggi.
Il sistema su cui ho eseguito la prova è un portatile Dell Inspiron 9400 con Centrino Duo, Intel T7200 4Mb Cache 2Ghz, Ram 2Gb 667Mhz. Sistema operativo Windows XP pro SP3.

Questo è il risultato del primo test, usato come riscaldamento per le vm:

Versione Compilatore Secondi
Python 2.6.4 7,5
Ruby 1.9.1 p129 i386-mingw32 8,2
JRuby 1.4.0 Client VM 1.6.0_15 [x86-java] 9,0
Python 3.1.1 9,1
Ruby 1.9.1 p243 i386-mingw32 9,6
IronRuby 0.9.3.0 .NET 2.0.0.0 20,3
Ruby 1.9.1 p376 i386-mswin32 20,9
Ruby 1.8.6 p368 i386-mingw32 22,9
IronPython 2.6 .NET 2.0.0.0 225,4
Jython 2.5.1 Client VM 1.6.0_15 [x86-java] Timeout

Benchmark senza warm up

Benchmark senza warm up

Il risultato che segue invece, si riferisce alla media delle tre rilevazioni successive al riscaldamento. Le prestazioni di JRuby migliorano del 23%:

Versione Compilatore Secondi
JRuby 1.4.0 Client VM 1.6.0_15 [x86-java] 6,9
Python 2.6.4 7,5
Ruby 1.9.1 p129 i386-mingw32 8,2
Python 3.1.1 9,0
Ruby 1.9.1 p243 i386-mingw32 10,0
IronRuby 0.9.3.0 .NET 2.0.0.0 18,9
Ruby 1.9.1 p376 i386-mswin32 20,6
Ruby 1.8.6 p368 i386-mingw32 23,2
IronPython 2.6 .NET 2.0.0.0 256,5
Jython 2.5.1 Client VM 1.6.0_15 [x86-java] Timeout

Rilevazioni dopo warm up

Rilevazioni dopo warm up

Ed ecco gli script. Ho cercato di ottimizzare le rispettive versioni e per fare ciò, ho dovuto creare due varianti per ogni linguaggio.

Ruby 1.8.6:

def strings_test(ntest)
  r1 = r2 = r3 = 0
  xstr = ""
  ntest.times do 
    #Create a string, add 'abcde1234_' until getting a str size 1000
    xstr = 'abcde1234_' * 10000
 
    #Make letters upcase 
    xstr.upcase!
 
    #Change '1234_' with '67890 ' (space at last position)
    #Now the repeated string should be 'ABCDE67890 '
    xstr.gsub! '1234_', '67890 '
 
    #Cast numbers from 29 upto size/2 to string and add it to xstr variable, ciclying for every number (not add all numbers one time)
    29.upto(xstr.size/2) {|n| xstr << n.to_s}
 
    #Check 1: Count 'A' char 
    #Check 2: Count '9' char 
    0.upto(xstr.size-1) do |n| 
      if xstr[n].chr() == 'A'
        r1+=1 
      elsif xstr[n].chr() == '9'
        r2+=1
      end
    end
 
    #Create an array from xstr using space to split
    r3 += xstr.split.size
 
  end
 
  return r1, r2, r3, xstr
end
 
def arrays_test(ntest, xstr)
  r1 = r2 = r3 = r4 = r5 = 0
  ntest.times do 
    #Clear ar then add 5000 times this element: "I", "am", "great", null, "or", "number", 1
    ar =  []
    5000.times do
      ['I', 'am', 'great', nil, 'or', 'number', 1].each {|a| ar << a}
    end
 
    #...then reverse elements to obtain this order: 1, "number", "or", null, "great", "am", "I"
    ar.reverse!
 
    #...then, count the element with value "great" using two separate cicle
    #the first starting from 31 until 2955 (bounty inclused)
    31.upto(2955) do |n|
      r1 += 1 if ar[n] == 'great'
    end
    #the second looping all the array elements
    ar.each {|n| r2+=1 if n == 'great'}
 
    #Loop inside and build a temporary string with index and value, without put it into a variable and only for elements <> null
    ar.each_index{|i| ar[i] ? "#{i} #{ar[i]}" : r3+=1 }
 
    #delete null value elements and take its size
    ar.compact!
    r4 += ar.size
 
    #then join elements with space and take its size
    r5 += ar.join(' ').size
 
  end
 
  return r1, r2, r3, r4, r5
end
 
def nums_test(ntest)
  r1 = r2 = 0
 
  ntest.times do 
    #Find all prime numbers from 8 to 95 step by 3 and sum all primes got, to check the result
    #51.upto(307) do |n| 
    (8..95).step(3) do |n|
      primes(n).each {|a| r1 += a}
    end
 
    #Calculate factorial numbers start from 2 to 42
    r2 = 0
    for n in 2..42
      r2 += fac(n)
    end
  end
 
  return r1, r2
end
 
#Primes must return an array of prime numbers
def primes(n)
  ar = []
  for x in (2..n)
    prime = true
    for y in (2..x-1)
      if x%y == 0
        prime = false
        break
      end
    end
    ar << x if prime
  end
  return ar
end
 
def fac(n) (1..n).inject{|total, current| total * current} end
 
# ---  START  ---
puts "\nWarming up..."
t1=t2=t3=0
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
puts "Check3: #{r3}"
puts "Check4: #{xstr.size}"
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
puts "Check3: #{r3}"
puts "Check4: #{r4}"
puts "Check5: #{r5}"
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
 
puts "\n1. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "\n2. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "\n3. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "-------------------------------------"
puts "Average Strings test - Elapsed %.3f" % (t1/3)
puts "Average Arrays test  - Elapsed %.3f" % (t2/3)
puts "Average Numeric test - Elapsed %.3f" % (t3/3)
puts "\nRuby Average elapsed time %.3f" % (t1/3+t2/3+t3/3)

Ruby 1.9.1:

def strings_test(ntest)
  r1 = r2 = r3 = 0
  xstr = ""
  ntest.times do 
    #Create a string, add 'abcde1234_' until getting a str size 1000
    xstr = 'abcde1234_' * 10000
 
    #Make letters upcase 
    xstr.upcase!
 
    #Change '1234_' with '67890 ' (space at last position)
    #Now the repeated string should be 'ABCDE67890 '
    xstr.gsub! '1234_', '67890 '
 
    #Cast numbers to string, from 29 up to size/2. Add it to xstr variable as well, ciclying for every number (not adding all numbers once)
    29.upto(xstr.size/2) {|n| xstr << n.to_s}
 
    #Check 1: Count 'A' char 
    #Check 2: Count '9' char 
    0.upto(xstr.size-1) do |n| 
      if xstr[n] == 'A'
        r1+=1 
      elsif xstr[n] == '9'
        r2+=1
      end
    end
 
    #Create an array from xstr using space to split, its size is the third check
    r3 += xstr.split.size
 
  end
 
  return r1, r2, r3, xstr
end
 
def arrays_test(ntest, xstr)
  r1 = r2 = r3 = r4 = r5 = 0
  ntest.times do 
    #Clear ar then add 5000 times this element: "I", "am", "great", null, "or", "number", 1
    ar =  []
    5000.times do
      ['I', 'am', 'great', nil, 'or', 'number', 1].each {|a| ar << a}
    end
 
    #...then reverse elements to obtain this order: 1, "number", "or", null, "great", "am", "I"
    ar.reverse!
 
    #...then, count the element with value "great" using two separate cicle
    #the first starting from 31 until 2955 (bounty inclused)
    31.upto(2955) do |n|
      r1 += 1 if ar[n] == 'great'
    end
    #the second looping all the array elements
    ar.each {|n| r2+=1 if n == 'great'}
 
    #Loop inside and build a temporary string with index and value, without put it into a variable and only for elements <> null
    ar.each_index{|i| ar[i] ? "#{i} #{ar[i]}" : r3+=1 }
 
    #delete null value elements and take its size
    ar.compact!
    r4 += ar.size
 
    #then join elements with space and take its size
    r5 += ar.join(' ').size
 
  end
 
  return r1, r2, r3, r4, r5
end
 
def nums_test(ntest)
  r1 = r2 = 0
 
  ntest.times do 
    #Find all prime numbers from 8 to 95 step by 3 (bounds included) and sum all primes got, to check the result
    #51.upto(307) do |n| 
    (8..95).step(3) do |n|
      primes(n).each {|a| r1 += a}
    end
 
    #Calculate factorial numbers start from 2 to 42
    r2 = 0
    for n in 2..42
      r2 += fac(n)
    end
  end
 
  return r1, r2
end
 
#Primes must return an array of prime numbers
def primes(n)
  ar = []
  for x in (2..n)
    prime = true
    for y in (2..x-1)
      if x%y == 0
        prime = false
        break
      end
    end
    ar << x if prime
  end
  return ar
end
 
def fac(n) (1..n).inject{|total, current| total * current} end
 
# ---  START  ---
puts "\nWarming up..."
t1=t2=t3=0
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
puts "Check3: #{r3}"
puts "Check4: #{xstr.size}"
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
puts "Check3: #{r3}"
puts "Check4: #{r4}"
puts "Check5: #{r5}"
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
 
puts "\n1. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "\n2. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "\n3. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "-------------------------------------"
puts "Average Strings test - Elapsed %.3f" % (t1/3)
puts "Average Arrays test  - Elapsed %.3f" % (t2/3)
puts "Average Numeric test - Elapsed %.3f" % (t3/3)
puts "\nRuby Average elapsed time %.3f" % (t1/3+t2/3+t3/3)

Python 2.6:

from time import time
#import psyco
#psyco.full()
#psyco.full(memory=100)
#psyco.profile(0.05, memory=100)
#psyco.profile(0.2)
 
 
def strings_test(ntest):
  r1 = r2 = r3 = 0
  xstr = ""
  for x in xrange(ntest):
    #Create a string, add 'abcde1234_' until getting a xstr size 1000
    xstr = 'abcde1234_' * 10000
 
    #Make letters upcase 
    xstr = xstr.upper()
 
    #Change '1234_' with '67890 ' (space at last position)
    #Now the repeated string should be 'ABCDE67890 '
    xstr = xstr.replace('1234_', '67890 ')
 
    #Cast numbers to string, from 29 up to size/2. Add it to xstr variable as well, ciclying for every number (not adding all numbers once)
    for y in xrange(29,int(len(xstr)/2) + 1):
        xstr += "%s" %y
 
    #Result 1: Count 'A' char 
    #Result 2: Count '9' char 
    for y in xrange(0, len(xstr)):
      if xstr[y] == 'A':
        r1+=1 
      elif xstr[y] == '9':
        r2+=1
 
    #Create an array from xstr using space to split
    r3 += len(xstr.split())
 
 
  return r1, r2, r3, xstr
 
#Slower than other version
def multiremove(ar, what):
  i = 0
  for el in ar:
    if el == what:
      del ar[i]
    i+=1
 
#Ugly but a bit faster
def multiremove2(ar, what):
  todel = [] 
  for y in xrange(0,len(ar)):
    if ar[y] == what:
       todel.append(y)
  todel.reverse()
  for y in todel:
     ar.pop(y)
 
def arrays_test(ntest, xstr):
  r1 = r2 = r3 = r4 = r5 = 0
  for x in xrange(ntest):
    #Clear ar then add 5000 times this element: "I", "am", "great", null, "or", "number", 1
    ar = []
    for y in xrange(0, 5000):
      ar.extend(["I", "am", "great", None, "or", "number", 1])
 
    #...then reverse elements to obtain this order: 1, "number", "or", null, "great", "am", "I"
    ar.reverse()
 
    #...then, count the element with value "great" using two separate cicle
    #the first starting from 31 until 2955 (bounty included)
    for y in xrange(31,2955):
      if ar[y] == "great": r1 +=1
 
    #the second looping all the array elements
    for y in xrange(0, len(ar)):
      if ar[y] == "great": r2+=1
 
    #Loop inside and build a temporary string with index and value, without put it into a variable and only for elements <> null
    for y in xrange(0, len(ar)):
      if ar[y]:
        "%s %s" %(y, ar[y])
      else:
        r3+=1
 
    #delete null value elements and take its size
    multiremove2(ar, None)
    r4 += len(ar)
 
    #then join elements with space and take its size
    r5 += len(" ".join(str(n) for n in ar))
 
  return r1, r2, r3, r4, r5
 
def nums_test(ntest):
  r1 = r2 = 0
  for x in xrange(ntest):
    #Find all prime numbers from 8 to 95 step by 3 (bounds included) and sum all primes got, to check the result
    for n in xrange(8, 96, 3):
      for prime in primes(n):
        r1 += prime
    fac = lambda n:[1,0][n>0] or fac(n-1)*n
    #Calculate factorial numbers start from 2 to 42 (bounds included)
    r2 = 0
    for n in xrange(2, 43):
      r2 += fac(n)
 
  return r1, r2
 
#Primes must return an array of prime numbers
def primes(n):
  ar = []
  for x in xrange(2, n+1):
    prime = True
    for y in xrange(2, x):
      if x%y == 0:
        prime = False
        break
    if prime:
      ar.append(x)
  return ar
 
# ---  START  ---
print "\nWarming up..."
t1=t2=t3=0
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print "Strings test - Elapsed %.3f" % (p1)
print "Check1: %s" %r1
print "Check2: %s" %r2
print "Check3: %s" %r3
print "Check4: %d" %(len(xstr))
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print  "Arrays test - Elapsed %.3f" % (p2)
print "Check1: %s" %r1
print "Check2: %s" %r2
print "Check3: %s" %r3
print "Check4: %s" %r4
print "Check5: %s" %r5
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print "Numeric test  - Elapsed %.3f" % (p3)
print "Check1: %s" %r1
print "Check2: %s" %r2
 
print  "Python Partial elapsed time %.3f" % (p1+p2+p3)
 
print "\n1. Starting Python tests..."
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print "Strings test - Elapsed %.3f" % (p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print  "Arrays test  - Elapsed %.3f" % (p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print "Numeric test - Elapsed %.3f" % (p3)
 
print  "Python Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
print "\n2. Starting Python tests..."
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print "Strings test - Elapsed %.3f" % (p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print  "Arrays test  - Elapsed %.3f" % (p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print "Numeric test - Elapsed %.3f" % (p3)
 
print  "Python Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
print "\n3. Starting Python tests..."
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print "Strings test - Elapsed %.3f" % (p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print  "Arrays test  - Elapsed %.3f" % (p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print "Numeric test - Elapsed %.3f" % (p3)
 
print  "Python Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
print "-------------------------------------"
print "Average Strings test - Elapsed %.3f" % (t1/3)
print "Average Arrays test  - Elapsed %.3f" % (t2/3)
print "Average Numeric test - Elapsed %.3f" % (t3/3)
print "Python Average elapsed time %.3f" % (t1/3+t2/3+t3/3)

Python 3.1:

from time import time
#import psyco
#psyco.full()
#psyco.full(memory=100)
#psyco.profile(0.05, memory=100)
#psyco.profile(0.2)
 
 
def strings_test(ntest):
  r1 = r2 = r3 = 0
  xstr = ""
  for x in range(ntest):
    #Create a string, add 'abcde1234_' until getting a xstr size 1000
    xstr = 'abcde1234_' * 10000
 
    #Make letters upcase 
    xstr = xstr.upper()
 
    #Change '1234_' with '67890 ' (space at last position)
    #Now the repeated string should be 'ABCDE67890 '
    xstr = xstr.replace('1234_', '67890 ')
 
    #Cast numbers from 29 upto 1028 to string and add it to xstr variable, ciclying for every number (not add all numbers one time)
    for y in range(29,int(len(xstr)/2) + 1):
        xstr += "%s" %y
 
    #Result 1: Count 'A' char 
    #Result 2: Count '9' char 
    for y in range(0, len(xstr)):
      if xstr[y] == 'A':
        r1+=1 
      elif xstr[y] == '9':
        r2+=1
 
    #Create an array from xstr using space to split
    r3 += len(xstr.split())
 
 
  return r1, r2, r3, xstr
 
#Slower than other version
def multiremove(ar, what):
  i = 0
  for el in ar:
    if el == what:
      del ar[i]
    i+=1
 
#Ugly but a bit faster
def multiremove2(ar, what):
  todel = [] 
  for y in range(0,len(ar)):
    if ar[y] == what:
       todel.append(y)
  todel.reverse()
  for y in todel:
     ar.pop(y)
 
def arrays_test(ntest, xstr):
  r1 = r2 = r3 = r4 = r5 = 0
  for x in range(ntest):
    #Clear ar then add 5000 times this element: "I", "am", "great", null, "or", "number", 1
    ar = []
    for y in range(0, 5000):
      ar.extend(["I", "am", "great", None, "or", "number", 1])
 
    #...then reverse elements to obtain this order: 1, "number", "or", null, "great", "am", "I"
    ar.reverse()
 
    #...then, count the element with value "great" using two separate cicle
    #the first starting from 31 until 2955 (bounty included)
    for y in range(31,2955):
      if ar[y] == "great": r1 +=1
 
    #the second looping all the array elements
    for y in range(0, len(ar)):
      if ar[y] == "great": r2+=1
 
    #Loop inside and build a temporary string with index and value, without put it into a variable and only for elements <> null
    for y in range(0, len(ar)):
      if ar[y]:
        "%s %s" %(y, ar[y])
      else:
        r3+=1
 
    #delete null value elements and take its size
    multiremove2(ar, None)
    r4 += len(ar)
 
    #then join elements with space and take its size
    r5 += len(" ".join(str(n) for n in ar))
 
  return r1, r2, r3, r4, r5
 
def nums_test(ntest):
  r1 = r2 = 0
  for x in range(ntest):
    #Find all prime numbers from 8 to 95 step by 3 (bounds included) and sum all primes got, to check the result
    for n in range(8, 96, 3):
      for prime in primes(n):
        r1 += prime
    fac = lambda n:[1,0][n>0] or fac(n-1)*n
    #Calculate factorial numbers start from 2 to 42 (bounds included)
    r2 = 0
    for n in range(2, 43):
      r2 += fac(n)
 
  return r1, r2
 
#Primes must return an array of prime numbers
def primes(n):
  ar = []
  for x in range(2, n+1):
    prime = True
    for y in range(2, x):
      if x%y == 0:
        prime = False
        break
    if prime:
      ar.append(x)
  return ar
 
# ---  START  ---
print("\nWarming up...")
t1=t2=t3=0
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print("Strings test - Elapsed %.3f" % p1)
print("Check1: %s" % r1)
print("Check2: %s" % r2)
print("Check3: %s" % r3)
print("Check4: %d" % len(xstr))
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print("Arrays test - Elapsed %.3f" % p2)
print("Check1: %s" % r1)
print("Check2: %s" % r2)
print("Check3: %s" % r3)
print("Check4: %s" % r4)
print("Check5: %s" % r5)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print("Numeric test - Elapsed %.3f" % p3)
print("Check1: %s" % r1)
print("Check2: %s" % r2)
 
print( "Python Partial elapsed time %.3f" % (p1+p2+p3))
 
print("\n1. Starting Python tests...")
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print("Strings test - Elapsed %.3f" % p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print( "Arrays test  - Elapsed %.3f" % p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print("Numeric test - Elapsed %.3f" % p3)
 
print( "Python Partial elapsed time %.3f" % (p1+p2+p3))
t1+=p1;t2+=p2;t3+=p3
 
print("\n2. Starting Python tests...")
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print("Strings test - Elapsed %.3f" % p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print( "Arrays test  - Elapsed %.3f" % p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print("Numeric test - Elapsed %.3f" % p3)
 
print( "Python Partial elapsed time %.3f" % (p1+p2+p3))
t1+=p1;t2+=p2;t3+=p3
 
print("\n3. Starting Python tests...")
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print("Strings test - Elapsed %.3f" % p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print( "Arrays test  - Elapsed %.3f" % p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print("Numeric test - Elapsed %.3f" % p3)
 
print( "Python Partial elapsed time %.3f" % (p1+p2+p3))
t1+=p1;t2+=p2;t3+=p3
 
print("-------------------------------------")
print("Average Strings test - Elapsed %.3f" % (t1/3))
print("Average Arrays test  - Elapsed %.3f" % (t2/3))
print("Average Numeric test - Elapsed %.3f" % (t3/3))
print("Python Average elapsed time %.3f" % (t1/3+t2/3+t3/3))
 

Comparazione linguaggi script per la geometria frattale

23 Aug

In questo articolo metterò a confronto le ultime incarnazioni di ruby, con le ultime di python, groovy, php, lua, perl e anche java, per avere un metro di paragone con un linguaggio precompilato. Vedremo, infatti, come si comportano i linguaggi di script applicati alla geometria frattale, più precisamente un algoritmo della famiglia di Mandelbrot.
Navigando, ho trovato un confronto molto interessante ma un pò datato, risale a più di due anni fa. Da allora sono cambiate un pò di cose e ne ho approfittato per fare un aggiornamento anche se non includerò tutti quei linguaggi molti dei quali semi sconosciuti. Questa è l’occasione per mettere a confronto ruby e python anche nelle loro versioni java e .net, un intenzione che avevo già da un pò di tempo.

Usare un frattale come benchmark è oltretutto comodo: se un tentativo di ottimizzazione non va a buon fine se ne ha subito l’evidenza ed essendo disegnato in tempo reale, si riesce a percepire la velocità di esecuzione. Il frattale è disegnato in ascii anche perchè l’utilizzo di librerie esterne ne avrebbe drogato l’esito.

                                       *
                                       *
                                       *
                                       *
                                       *
                                      ***
                                     *****
                                     *****
                                      ***
                                       *
                                   *********
                                 *************
                                ***************
                             *********************
                             *********************
                              *******************
                              *******************
                              *******************
                              *******************
                            ***********************
                              *******************
                              *******************
                             *********************
                              *******************
                              *******************
                               *****************
                                ***************
                                 *************
                                   *********
                                       *
                                ***************
                            ***********************
                         * ************************* *
                         *****************************
                      * ******************************* *
                       *********************************
                      ***********************************
                    ***************************************
               *** ***************************************** ***
               *************************************************
                ***********************************************
                 *********************************************
                 *********************************************
                ***********************************************
                ***********************************************
              ***************************************************
               *************************************************
               *************************************************
              ***************************************************
              ***************************************************
         *    ***************************************************    *
       *****  ***************************************************  *****
       ****** *************************************************** ******
      ******* *************************************************** *******
    ***********************************************************************
    ********* *************************************************** *********
       ****** *************************************************** ******
       *****  ***************************************************  *****
              ***************************************************
              ***************************************************
              ***************************************************
              ***************************************************
               *************************************************
               *************************************************
              ***************************************************
                ***********************************************
                ***********************************************
                  *******************************************
                   *****************************************
                 *********************************************
                **** ****************** ****************** ****
                 ***  ****************   ****************  ***
                  *    **************     **************    *
                         ***********       ***********
                         **  *****           *****  **
                          *   *                 *   *

Questi sono i dati del sistema:
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

Questi sono i risultati prestazionali ottenuti da una media di cinque rilevazioni catturate dopo qualche tentativo (non mi sono fidato dello startup delle VM):

Linguaggio      Tempo (in secondi)  n più lento di 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

Questo è il grafico, naturalmente valori più bassi indicano una prestazione migliore

Chart

Questi sono gli script usati per generare il frattale, andavano benissimo quelli di Erik Wrenholt, mi sono limitato a qualche semplice modifica per far funzionare python 3.1 o per migliorare lievemente la già ottima leggibilità in ruby e 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
// 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);

Commenti:

La velocità di Lua è ormai nota, solamente 5 volte più lento rispetto al codice java compilato, il miglior risultato. La sua semplicità è la sua forza, forse è proprio questo che lo rende così veloce? E’ stato adottato dalla Blizzard all’interno del gioco World of Warcraft e se l’hanno fatto loro un motivo ci sarà. Non è ad oggetti o meglio, nativamente non li supporta anche se c’è il progetto LOOP che lo estende a questo modello di programmazione.
Php e Perl non hanno bisogno di commenti.
Tra le versioni C di Ruby e Python è chiaramente avanti quest’ultimo. Il paragone equo sarebbe la Rb1.8.6 con la Py2.6.2 e la Rb1.9.1 con la Py3.1.1.
La sfida tra le versioni che sfruttalo la Java VM: Groovy, Jython e JRuby, vede in vantaggio quest’ultimo. Groovy è molto indietro come prestazioni ma il dubbio più grosso che ho è: ma a chi è destinato? Come sintassi non è male ma ruby è ancora più scorrevole e poi ha quel rake che è tanto comodo per tante cose.
Le versioni ruby e python per .Net vede incredibilmente avanti IronPython! Ma che gli hanno messo dentro, la dinamite? Sarà molto interessante esaminare il nuovo framework MVC di ASP.NET da poco arrivato alla versione 1 e che sarà incluso nel framework .Net 4, esistono progetti sia per IronRuby che per IronPython.
Se questo articolo è risultato interessante, forse potrai trovare qualcos’altro tra gli annunci del mio sponsor, si trova nella colonna a destra, grazie!