Non si può negare che la versatilità sia una delle sue caratteristiche; un vero multipiattaforma. Ci sono interpreti per molti sistemi operativi e oltre alla versione classica in C++ abbiamo la valida alternativa di JRuby per il mondo java e infine Ironruby per il framework .NET di Microsoft, arrivato in questi ultimi giorni ad una versione abbastanza matura.
Niente male, pensiamo ai benefici che un’azienda potrebbe avere: un linguaggio semplice da imparare ma molto potente, ha un ottimo framework (uno su tutti, Rails) per sviluppare rapidamente applicazioni disponibili per esempio nella intranet e in aggiunta a tutto questo, la possibilità di usare le librerie java o .net.
In questo articolo vedremo come si comportano questi quattro interpreti:
- Ruby 1.8.6 patch 368 aggiornato al 2009-03-31
- Ruby 1.9.1 patch 129 aggiornato al 2009-05-12 revisione 23412
- jRuby 1.3.1 (ruby 1.8.6p287) 2009-06-15 Client VM 1.6.0 update 14
- IronRuby 0.9.0.0 on .NET 2.0.0.0
Lo scopo: per scoprire le differenze prestazionali principalmente nell’ambito del singolo interprete. Ci sono metodi e tecniche che portano allo stesso risultato e senza simili test difficilmente si può stabilire qual’è la pratica migliore.
Nei test che vedremo, mi sono concentrato sulla velocità di elaborazione controllando solo grossolanamente la quantità di memoria utilizzata.
Il sistema: La macchina fisica è un Windows XP Professional SP3 32bit con un Intel E7300 dual core con 3Mb di cache e 3,25Gb di ram.
Sistema fisico
I test giravano su un sistema virtualizzato con MS Virtual PC 2007, os sempre XP Pro, Java SDK 6.14, Framework .NET 3.5 SP1, processore singolo core, memoria 768Mb. Solo il test più pesante sugli hash l’ho ripetuto con 2Gb.
I benchmarks sono divisi in quattro categorie:
- Stringhe
- Numeri
- Array
- Hash
Li ho creati io e si limitano ad eseguire operazioni molto semplici. Alla fine c’è un totale ma non deve essere inteso come un indice sull’effettiva prestazione dell’interprete perchè questa cambia molto in base ai test scelti e quelli che ho utilizzati io non è detto che siano condizioni riscontrate nell’uso reale.
Le stringhe
Questo è il primo script:
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | require "benchmark" include Benchmark Benchmark.bm(21, "--- Total:") do|b| puts "Concat 1.000.000:" n=1_000_000 t1 = b.report("+") do n.times { "a "+"b "+"c "+"d "+"e "; "f "+"g" } end t1 += b.report("<<") do n.times { "a "<<"b "<<"c "<<"d "<<"e "; "f "<<"g" } end t1 += b.report("#{}") do sa="a"; sb="b"; sc="c"; sd="d"; se="e" n.times { "#{sa} #{sb} #{sc} #{sd} #{se}"; "#{sb} #{sc}" } end puts "Add 100.000:" n=100_000 t2 = b.report("+=") do a = "" n.times { a += "." } end t2 += b.report("<<") do a = "" n.times { a << "." } end t2 += b.report("a = a + '.'") do a = "" n.times { a = a + "." } end t2 += b.report("#{}") do a = "" n.times { a = "#{a}." } end puts "Other 100.000:" n=100_000 str="" t3 = b.report("* 100:") do n.times { str = " abc def ghi rn" * 100 } end t3 += b.report("capitalize:") do n.times { str.capitalize } end t3 += b.report("upcase:") do n.times { str.upcase } end t3 += b.report("chomp:") do n.times { str.chomp } end t3 += b.report("include:") do n.times { str.include?("ghi");str.include?("qwertyuiopasdfghjkl") } end t3 += b.report("index:") do n.times { str.index("ghi");str.index("qwertyuiopasdfghjkl") } end t3 += b.report("sub:") do n.times { str.sub("ghi", "GGHHII") } end t3 += b.report("gsub:") do n.times { str.gsub("ghi", "GGHHII") } end t3 += b.report("[x..y]:") do n.times {|x| str[0..2];str[5..15];str[6..26];str[10..50] } end t3 += b.report("slice:") do n.times {|x| str.slice(0..2);str.slice(5..15);str.slice(6..26);str.slice(10..50) } end t3 += b.report("strip:") do n.times {|x| " 1 2 3 4 5 ".strip } end t3 += b.report("Each:") do n.times { str.each_line{|x| x } } end puts "Cast 1.000.000:" n=1_000_000 str="abcd1234" t4 = b.report(".to_i:") do n.times { str.to_i } end t4 += b.report(".to_sym:") do n.times { str.to_sym } end n=100_000 str="abc123 " * 100 t4 += b.report("split:") do n.times { str.split } end [t1+t2+t3+t4] end |
Questi sono i risultati in ordine di interprete, dal primo al quarto:
Ruby 1.8.6
C:ProgettiRubybench>ruby bench_str.rb
user system total real
Concat 1.000.000:
+ 3.525000 0.000000 3.525000 ( 3.555325)
<< 2.864000 0.000000 2.864000 ( 2.884320)
#{} 3.565000 0.010000 3.575000 ( 3.615415)
Add 100.000:
+= 5.257000 4.306000 9.563000 ( 9.724565)
<< 0.030000 0.010000 0.040000 ( 0.040060)
a = a + '.' 5.398000 4.376000 9.774000 ( 9.884805)
#{} 5.328000 2.474000 7.802000 ( 7.901835)
Other 100.000:
* 100: 0.551000 0.380000 0.931000 ( 0.981470)
capitalize: 0.951000 0.361000 1.312000 ( 1.311965)
upcase: 2.844000 0.490000 3.334000 ( 3.365040)
chomp: 0.491000 0.301000 0.792000 ( 0.861290)
include: 0.631000 0.000000 0.631000 ( 0.630945)
index: 0.611000 0.000000 0.611000 ( 0.610915)
sub: 1.181000 0.410000 1.591000 ( 1.602400)
gsub: 19.989000 1.623000 21.612000 ( 21.842715)
[x..y]: 0.351000 0.000000 0.351000 ( 0.360540)
slice: 0.350000 0.000000 0.350000 ( 0.350525)
strip: 0.090000 0.000000 0.090000 ( 0.090135)
Each: 7.711000 0.000000 7.711000 ( 7.761625)
Cast 1.000.000:
.to_i: 0.221000 0.000000 0.221000 ( 0.220330)
.to_sym: 0.240000 0.000000 0.240000 ( 0.240360)
split: 6.229000 0.010000 6.239000 ( 6.269390)
--- Total: 68.408000 14.751000 83.159000 ( 84.105970)
Ruby 1.9.1
C:ProgettiRubybench>ruby bench_str.rb
user system total real
Concat 1.000.000:
+ 1.932000 0.000000 1.932000 ( 1.992985)
<< 1.633000 0.000000 1.633000 ( 1.672505)
#{} 2.183000 0.000000 2.183000 ( 2.213315)
Add 100.000:
+= 5.538000 4.136000 9.674000 ( 9.884805)
<< 0.030000 0.000000 0.030000 ( 0.030045)
a = a + '.' 5.368000 4.346000 9.714000 ( 9.884805)
#{} 6.529000 4.246000 10.775000 ( 11.096620)
Other 100.000:
* 100: 0.491000 0.400000 0.891000 ( 0.891335)
capitalize: 4.406000 0.501000 4.907000 ( 4.977455)
upcase: 0.671000 0.501000 1.172000 ( 1.171755)
chomp: 0.541000 0.340000 0.881000 ( 0.911365)
include: 0.110000 0.000000 0.110000 ( 0.110165)
index: 0.120000 0.000000 0.120000 ( 0.120180)
sub: 0.731000 0.371000 1.102000 ( 1.111665)
gsub: 7.361000 0.991000 8.352000 ( 8.512750)
[x..y]: 0.200000 0.010000 0.210000 ( 0.210315)
slice: 0.170000 0.000000 0.170000 ( 0.170255)
strip: 0.090000 0.000000 0.090000 ( 0.090135)
Each: 6.359000 0.020000 6.379000 ( 6.419615)
Cast 1.000.000:
.to_i: 0.171000 0.000000 0.171000 ( 0.170255)
.to_sym: 0.290000 0.000000 0.290000 ( 0.330495)
split: 3.575000 0.000000 3.575000 ( 3.595385)
--- Total: 48.499000 15.862000 64.361000 ( 65.568205)
JRuby
C:ProgettiRubybench>jruby bench_str.rb
user system total real
Concat 1.000.000:
+ 1.142000 0.000000 1.142000 ( 1.101000)
<< 0.932000 0.000000 0.932000 ( 0.942000)
#{} 0.430000 0.000000 0.430000 ( 0.430000)
Add 100.000:
+= 7.962000 0.000000 7.962000 ( 7.962000)
<< 0.020000 0.000000 0.020000 ( 0.020000)
a = a + '.' 7.542000 0.000000 7.542000 ( 7.542000)
#{} 16.324000 0.000000 16.324000 ( 16.324000)
Other 100.000:
* 100: 0.140000 0.000000 0.140000 ( 0.140000)
capitalize: 0.781000 0.000000 0.781000 ( 0.781000)
upcase: 1.382000 0.000000 1.382000 ( 1.382000)
chomp: 0.051000 0.000000 0.051000 ( 0.051000)
include: 0.240000 0.000000 0.240000 ( 0.240000)
index: 0.230000 0.000000 0.230000 ( 0.230000)
sub: 0.381000 0.000000 0.381000 ( 0.391000)
gsub: 3.816000 0.000000 3.816000 ( 3.816000)
[x..y]: 0.100000 0.000000 0.100000 ( 0.100000)
slice: 0.120000 0.000000 0.120000 ( 0.120000)
strip: 0.040000 0.000000 0.040000 ( 0.040000)
Each: 2.333000 0.000000 2.333000 ( 2.333000)
Cast 1.000.000:
.to_i: 0.470000 0.000000 0.470000 ( 0.470000)
.to_sym: 0.191000 0.000000 0.191000 ( 0.191000)
split: 1.622000 0.000000 1.622000 ( 1.622000)
--- Total: 46.249000 0.000000 46.249000 ( 46.227999)
IronRuby
C:ProgettiRubybench>ir bench_str.rb
user system total real
Concat 1.000.000:
+ 2.804032 0.070101 2.874133 ( 2.954425)
<< 1.101584 0.000000 1.101584 ( 1.101650)
#{} 1.331915 0.000000 1.331915 ( 1.342010)
Add 100.000:
+= 50.502619 4.836955 55.339574 ( 56.043940)
<< 0.040058 0.000000 0.040058 ( 0.040060)
a = a + '.' 50.662850 4.616638 55.279488 ( 56.013895)
#{} 51.173584 4.666710 55.840294 ( 56.634825)
Other 100.000:
* 100: 0.500720 0.000000 0.500720 ( 0.500750)
capitalize: 2.503600 0.010014 2.513614 ( 2.583870)
upcase: 6.078741 0.000000 6.078741 ( 6.199285)
chomp: 0.200288 0.000000 0.200288 ( 0.200300)
include: 4.216062 0.000000 4.216062 ( 4.246360)
index: 4.135947 0.000000 4.135947 ( 4.206300)
sub: 1.462102 0.000000 1.462102 ( 1.492235)
gsub: 8.692499 0.020029 8.712528 ( 8.773140)
[x..y]: 0.290418 0.000000 0.290418 ( 0.290435)
slice: 0.230331 0.010014 0.240346 ( 0.260390)
strip: 0.070101 0.000000 0.070101 ( 0.070105)
Each: 25.015971 0.050072 25.066043 ( 25.357980)
Cast 1.000.000:
.to_i: 0.220317 0.000000 0.220317 ( 0.220330)
.to_sym: 0.280403 0.000000 0.280403 ( 0.280420)
split: 4.446394 0.010014 4.456408 ( 4.516765)
--- Total: 215.960536 14.290549 230.251085 (233.329469)
Questo è il riepilogo dei totali:
Ruby 1.8.6
--- Total: 68.408000 14.751000 83.159000 ( 84.105970)
Ruby 1.9.1
--- Total: 48.499000 15.862000 64.361000 ( 65.568205)
Jruby
--- Total: 46.249000 0.000000 46.249000 ( 46.227999)
Ironruby
--- Total: 215.960536 14.290549 230.251085 (233.329469)
Commento: Per la concatenazione, in tutti i casi prevale l'operatore << mentre includere le variabili nelle stringhe con #{}, sarà forse efficiente come uso di memoria ma in quanto a prestazioni è in coda agli altri. Ironruby fatica con le stringhe, è alto infatti il divario con particolari operatori anche se basterebbe usare << per quasi annullare il divario. Un pò di fatica anche sul ciclo delle righe se confrontato con gli altri tre. Molto bene ruby 1.9.1 con prestazioni simili a Jruby ma un consumo di memoria di soli 5Mb contro 30 della versione java. Anche la versione 1.8.6 non è niente male, ha perso tempo con gsub (soprattutto rispetto a jruby!).
I numeri
Lo script:
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | require "benchmark" include Benchmark Benchmark.bm(21, "--- Total:") do|b| puts "Integer" puts "Arithmetic operations 10.000.000:" n=10_000_000 t1 = b.report("x + 2") do a = 0 n.times {|x| a = x + 2 } end t1 += b.report("x - 1") do n.times {|x| a = x - 1 } end t1 += b.report("x * 3") do n.times {|x| a = x * 3 } end t1 += b.report("x / 2") do n.times {|x| a = x / 2 } end t1 += b.report("x ** 2") do n.times {|x| a = x ** 2 } end t1 += b.report("x % 360") do n.times {|x| x % 360 } end t1 += b.report("Cast") do n.times {|x| x.to_s } n.times {|x| x.to_f } end puts "Add 10.000.000:" n=10_000_000 t2 = b.report("+=") do a = 0 n.times { a += 1 } end t2 += b.report("a = a + 1") do a = 0 n.times { a = a + 1 } end t2 += b.report("<<") do a = 0 n.times { a << 1 } end t2 += b.report(".next") do a = 0 n.times { a = a.next } end puts "Float" puts "Arithmetic operations 10.000.000:" n=10_000_000 t3 = b.report("x + 1.234567") do a = 0 n.times {|x| a = x + 1.234567 } end t3 += b.report("x - 0.135799") do a = 0 n.times {|x| a = x - 0.135799 } end t3 += b.report("x * 0.987654") do a = 0 n.times {|x| a = x * 0.987654 } end t3 += b.report("x / 1.975313") do a = 0 n.times {|x| a = x / 1.975313 } end t3 += b.report("x ** 1.987654") do a = 0 n.times {|x| a = x ** 1.987654 } end t3 += b.report("Cast") do n.times {|x| x.to_s } n.times {|x| x.to_i } end [t1+t2+t3] end |
Ruby 1.8.6
C:ProgettiRubybench>ruby bench_num.rb
user system total real
Integer
Arithmetic operations 10.000.000:
x + 2 3.154000 0.000000 3.154000 ( 3.194785)
x - 1 3.365000 0.000000 3.365000 ( 3.415115)
x * 3 3.415000 0.000000 3.415000 ( 3.495235)
x / 2 3.475000 0.000000 3.475000 ( 3.495235)
x ** 2 14.771000 0.010000 14.781000 ( 14.952395)
x % 360 2.914000 0.000000 2.914000 ( 3.004500)
Cast 11.847000 0.000000 11.847000 ( 11.987955)
Add 10.000.000:
+= 2.544000 0.000000 2.544000 ( 2.583870)
a = a + 1 2.524000 0.000000 2.524000 ( 2.533795)
<< 2.233000 0.000000 2.233000 ( 2.253375)
.next 1.963000 0.000000 1.963000 ( 1.982970)
Float
Arithmetic operations 10.000.000:
x + 1.234567 3.885000 0.000000 3.885000 ( 3.985970)
x - 0.135799 3.886000 0.000000 3.886000 ( 3.945910)
x * 0.987654 3.895000 0.000000 3.895000 ( 3.945910)
x / 1.975313 12.378000 0.010000 12.388000 ( 12.588855)
x ** 1.987654 5.057000 0.000000 5.057000 ( 5.147710)
Cast 11.106000 0.030000 11.136000 ( 11.286905)
--- Total: 92.412000 0.050000 92.462000 ( 93.800490)
Ruby 1.9.1
C:ProgettiRubybench>ruby bench_num.rb
user system total real
Integer
Arithmetic operations 10.000.000:
x + 2 0.981000 0.000000 0.981000 ( 0.991485)
x - 1 0.901000 0.000000 0.901000 ( 0.911365)
x * 3 0.962000 0.000000 0.962000 ( 0.961440)
x / 2 0.911000 0.000000 0.911000 ( 0.921380)
x ** 2 4.316000 0.000000 4.316000 ( 4.366540)
x % 360 0.881000 0.000000 0.881000 ( 0.961440)
Cast 4.727000 0.020000 4.747000 ( 5.217815)
Add 10.000.000:
+= 0.952000 0.000000 0.952000 ( 0.951425)
a = a + 1 0.901000 0.010000 0.911000 ( 0.951425)
<< 1.312000 0.000000 1.312000 ( 1.342010)
.next 1.312000 0.020000 1.332000 ( 1.402100)
Float
Arithmetic operations 10.000.000:
x + 1.234567 2.103000 0.000000 2.103000 ( 2.233345)
x - 0.135799 1.983000 0.000000 1.983000 ( 2.013015)
x * 0.987654 2.042000 0.000000 2.042000 ( 2.053075)
x / 1.975313 2.183000 0.000000 2.183000 ( 2.243360)
x ** 1.987654 3.174000 0.000000 3.174000 ( 3.184770)
Cast 4.106000 0.000000 4.106000 ( 4.146210)
--- Total: 33.747000 0.050000 33.797000 ( 34.852200)
JRuby
C:ProgettiRubybench>jruby bench_num.rb
user system total real
Integer
Arithmetic operations 10.000.000:
x + 2 2.043000 0.000000 2.043000 ( 1.863000)
x - 1 1.803000 0.000000 1.803000 ( 1.803000)
x * 3 1.923000 0.000000 1.923000 ( 1.923000)
x / 2 2.153000 0.000000 2.153000 ( 2.153000)
x ** 2 5.899000 0.000000 5.899000 ( 5.899000)
x % 360 1.803000 0.000000 1.803000 ( 1.803000)
Cast 4.527000 0.000000 4.527000 ( 4.527000)
Add 10.000.000:
+= 1.682000 0.000000 1.682000 ( 1.682000)
a = a + 1 1.602000 0.000000 1.602000 ( 1.602000)
<< 1.302000 0.000000 1.302000 ( 1.302000)
.next 1.433000 0.000000 1.433000 ( 1.433000)
Float
Arithmetic operations 10.000.000:
x + 1.234567 2.363000 0.000000 2.363000 ( 2.363000)
x - 0.135799 2.404000 0.000000 2.404000 ( 2.404000)
x * 0.987654 2.153000 0.000000 2.153000 ( 2.153000)
x / 1.975313 4.487000 0.000000 4.487000 ( 4.487000)
x ** 1.987654 5.829000 0.000000 5.829000 ( 5.839000)
Cast 4.146000 0.000000 4.146000 ( 4.156000)
--- Total: 47.552000 0.000000 47.552000 ( 47.392000)
IronRuby
C:ProgettiRubybench>ir bench_num.rb
user system total real
Integer
Arithmetic operations 10.000.000:
x + 2 3.925645 0.060086 3.985731 ( 4.056075)
x - 1 1.652376 0.000000 1.652376 ( 1.662490)
x * 3 1.912750 0.000000 1.912750 ( 1.972955)
x / 2 1.982851 0.010014 1.992866 ( 2.013015)
x ** 2 3.895602 0.010014 3.905616 ( 3.975955)
x % 360 1.672405 0.010014 1.682419 ( 1.692535)
Cast 6.248986 0.010014 6.259000 ( 6.389570)
Add 10.000.000:
+= 1.672405 0.010014 1.682419 ( 1.712565)
a = a + 1 1.742506 0.000000 1.742506 ( 1.792685)
<< 1.472117 0.040058 1.512174 ( 1.532295)
.next 1.672405 0.000000 1.672405 ( 1.672505)
Float
Arithmetic operations 10.000.000:
x + 1.234567 1.932779 0.000000 1.932779 ( 1.932895)
x - 0.135799 1.952808 0.010014 1.962822 ( 2.033045)
x * 0.987654 1.992866 0.000000 1.992866 ( 1.992985)
x / 1.975313 3.825501 0.030043 3.855544 ( 3.925880)
x ** 1.987654 3.014334 0.000000 3.014334 ( 3.034545)
Cast 5.878453 0.000000 5.878453 ( 5.928880)
--- Total: 46.446787 0.190274 46.637061 ( 47.320875)
Riepilogo totali:
Ruby 1.8.6
--- Total: 92.412000 0.050000 92.462000 ( 93.800490)
Ruby 1.9.1
--- Total: 33.747000 0.050000 33.797000 ( 34.852200)
Jruby
--- Total: 47.552000 0.000000 47.552000 ( 47.392000)
Ironruby
--- Total: 46.446787 0.190274 46.637061 ( 47.320875)
Commento: Netto miglioramento della versione 1.9.1 che, con i numeri, è tre volte più veloce della 1.8.6. Anche gli altri due non sono male.
16/08/2009: Mi sono accorto di aver inserito erroneamente il metodo shift (<<) tra gli add.
24/08/2009: Avevo invertito i risultati della 1.8.6 con quelli della 1.9.1... in effetti mi sembravano un pò strani :-p
Gli array
Lo script:
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | require "benchmark" include Benchmark Benchmark.bm(21, "Total:") do|b| n=100_000 puts "Create 100.000:" t1 = b.report("%w()") do n.times { %w(a b c d f e g h j k i l m n o p q r s t u v w y z 0 1 2 3 4 5 6 7 8 9) } end t1 += b.report("%w''") do n.times { %w"a b c d f e g h j k i l m n o p q r s t u v w y z 0 1 2 3 4 5 6 7 8 9" } end t1 += b.report("split") do n.times { "a b c d f e g h j k i l m n o p q r s t u v w y z 0 1 2 3 4 5 6 7 8 9".split(' ') } end t1 += b.report("[str]") do n.times { ["a","b","c","d","f","e","g","h","j","k","i","l","m","n","o","p","q","r","s","t","u","v","w","y","z","0","1","2","3","4","5","6","7","8","9"] } end t1 += b.report("[num]") do n.times { [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4] } end t1 += b.report("Array.new(str)") do n.times { Array.new(35, "a") } end t1 += b.report("Array.new(num)") do n.times { Array.new(35, 0) } end t1 += b.report("Array.new(hash)") do n.times { Array.new(35, {}) } end n=100_000 puts "Add 100.000:" t2 = b.report("+= ['.']") do a = [] n.times { a += ["."] } end t2 += b.report("+= [0]") do a = [] n.times { a += [0] } end t2 += b.report("<< ['.']") do a = [] n.times { a << ["."] } end t2 += b.report("<< [0]") do a = [] n.times { a << [0] } end t2 += b.report("a = a+['.']") do a = [] n.times { a = a + ["."] } end t2 += b.report("a = a+[0]") do a = [] n.times { a = a + [0] } end n=100_000 puts "Concatenate 100.000:" t3 = b.report("[num]+") do n.times { [0,1,2,3,4]+[5,6,7,8,9]+[0,1,2,3,4,5,6,7,8,9] } end t3 += b.report("[str]+") do n.times { ["a","b","c","d","f"]+["e","g","h","j","k"]+["i","l","m","n","o","p","q","r","s","t"] } end t3 += b.report("[mix]+") do n.times { ["a","b","c","d","f"]+[5,6,7,8,9]+["i",0,"m",1,"o",2,"q",3,"s",4] } end t3 += b.report("[num]<<") do n.times { [0,1,2,3,4]<<[5,6,7,8,9]<<[0,1,2,3,4,5,6,7,8,9] } end t3 += b.report("[str]<<") do n.times { ["a","b","c","d","f"]<<["e","g","h","j","k"]<<["i","l","m","n","o","p","q","r","s","t"] } end t3 += b.report("[mix]<<") do n.times { ["a","b","c","d","f"]<<[5,6,7,8,9]<<["i",0,"m",1,"o",2,"q",3,"s",4] } end t3 += b.report("[num].concat") do n.times { [0,1,2,3,4].concat([5,6,7,8,9]).concat([0,1,2,3,4,5,6,7,8,9]) } end t3 += b.report("[str].concat") do n.times { ["a","b","c","d","f"].concat(["e","g","h","j","k"]).concat(["i","l","m","n","o","p","q","r","s","t"]) } end t3 += b.report("[mix].concat") do n.times { ["a","b","c","d","f"].concat([5,6,7,8,9]).concat(["i",0,"m",1,"o",2,"q",3,"s",4])} end t3 += b.report("union [num]") do n.times { [0,14,2,3,4,53,682] | [3,4,53,6,7,84,9] } end t3 += b.report("union [str]") do n.times { ["a","b","c","d","f"] | ["b","d","h","j","k"] } end a=Array.new(100, 0) n=1_000_000 puts "Read 1.000.000:" t4 = b.report("each:") do n.times { a.each{|x| x} } end t4 += b.report("map:") do n.times { a.map{|x| x} } end puts "Other 10.000:" n=10_000 a=["a",nil,0,"b",1,nil] * 500 t5 = b.report(".compact:") do n.times { a.compact } end t5 += b.report(".delete(nil):") do n.times { a.delete(nil)} end a=[] n.times {|x| a << x } t5 += b.report("delete:") do n.times {|x| a.delete(x) } end puts "-"*20 [t1+t2+t3+t4+t5] end |
Ruby 1.8.6
C:ProgettiRubybench>ruby bench_arr.rb
user system total real
Create 100.000:
%w() 0.300000 0.010000 0.310000 ( 0.320480)
%w'' 0.300000 0.000000 0.300000 ( 0.310465)
split 2.164000 0.010000 2.174000 ( 2.213315)
[str] 0.310000 0.000000 0.310000 ( 0.310465)
[num] 0.160000 0.030000 0.190000 ( 0.220330)
Array.new(str) 0.180000 0.010000 0.190000 ( 0.190285)
Array.new(num) 0.151000 0.030000 0.181000 ( 0.180270)
Array.new(hash) 0.270000 0.040000 0.310000 ( 0.310465)
Add 100.000:
+= ['.'] 22.472000 8.272000 30.744000 ( 31.487160)
+= [0] 20.800000 8.602000 29.402000 ( 30.004940)
<< ['.'] 0.070000 0.010000 0.080000 ( 0.090135)
<< [0] 0.070000 0.000000 0.070000 ( 0.070105)
a = a+['.'] 28.321000 7.351000 35.672000 ( 36.514690)
a = a+[0] 25.226000 7.480000 32.706000 ( 33.520205)
Concatenate 100.000:
[num]+ 0.451000 0.030000 0.481000 ( 0.490735)
[str]+ 0.581000 0.030000 0.611000 ( 0.640960)
[mix]+ 0.521000 0.030000 0.551000 ( 0.550825)
[num]<< 0.350000 0.020000 0.370000 ( 0.370555)
[str]<< 0.421000 0.031000 0.452000 ( 0.450675)
[mix]<< 0.420000 0.010000 0.430000 ( 0.430645)
[num].concat 0.341000 0.030000 0.371000 ( 0.380570)
[str].concat 0.491000 0.020000 0.511000 ( 0.510765)
[mix].concat 0.400000 0.020000 0.420000 ( 0.430645)
union [num] 1.032000 0.020000 1.052000 ( 1.051575)
union [str] 0.761000 0.080000 0.841000 ( 0.881320)
Read 1.000.000:
each: 16.934000 0.000000 16.934000 ( 17.145680)
map: 20.750000 1.181000 21.931000 ( 22.243315)
Other 10.000:
.compact: 0.401000 0.131000 0.532000 ( 0.530795)
.delete(nil): 4.246000 0.000000 4.246000 ( 4.316465)
delete: 4.937000 0.000000 4.937000 ( 5.017515)
--------------------
Total: 153.831000 33.478000 187.309000 (191.186350)
Ruby 1.9.1
C:ProgettiRubybench>ruby bench_arr.rb
user system total real
Create 100.000:
%w() 0.520000 0.000000 0.520000 ( 0.520780)
%w'' 0.541000 0.000000 0.541000 ( 0.550825)
split 0.781000 0.000000 0.781000 ( 0.791185)
[str] 0.511000 0.000000 0.511000 ( 0.520780)
[num] 0.020000 0.000000 0.020000 ( 0.020030)
Array.new(str) 0.170000 0.010000 0.180000 ( 0.190285)
Array.new(num) 0.140000 0.000000 0.140000 ( 0.140210)
Array.new(hash) 0.141000 0.030000 0.171000 ( 0.200300)
Add 100.000:
+= ['.'] 22.131000 9.553000 31.684000 ( 32.268330)
+= [0] 16.514000 8.422000 24.936000 ( 25.478160)
<< ['.'] 0.010000 0.020000 0.030000 ( 0.030045)
<< [0] 0.030000 0.000000 0.030000 ( 0.030045)
a = a+['.'] 17.856000 3.946000 21.802000 ( 22.323435)
a = a+[0] 17.024000 8.172000 25.196000 ( 25.788625)
Concatenate 100.000:
[num]+ 0.211000 0.020000 0.231000 ( 0.230345)
[str]+ 0.490000 0.000000 0.490000 ( 0.500750)
[mix]+ 0.341000 0.000000 0.341000 ( 0.340510)
[num]<< 0.140000 0.000000 0.140000 ( 0.140210)
[str]<< 0.421000 0.010000 0.431000 ( 0.460690)
[mix]<< 0.260000 0.000000 0.260000 ( 0.260390)
[num].concat 0.160000 0.000000 0.160000 ( 0.160240)
[str].concat 0.471000 0.000000 0.471000 ( 0.470705)
[mix].concat 0.320000 0.000000 0.320000 ( 0.320480)
union [num] 0.691000 0.020000 0.711000 ( 0.721080)
union [str] 0.952000 0.000000 0.952000 ( 0.961440)
Read 1.000.000:
each: 7.861000 0.000000 7.861000 ( 7.991970)
map: 13.169000 1.482000 14.651000 ( 14.822200)
Other 10.000:
.compact: 0.250000 0.130000 0.380000 ( 0.380570)
.delete(nil): 2.684000 0.000000 2.684000 ( 2.704050)
delete: 4.907000 0.000000 4.907000 ( 4.987470)
--------------------
Total: 109.717000 31.815000 141.532000 (144.306135)
JRuby
C:ProgettiRubybench>jruby bench_arr.rb
user system total real
Create 100.000:
%w() 0.251000 0.000000 0.251000 ( 0.211000)
%w'' 0.190000 0.000000 0.190000 ( 0.190000)
split 0.370000 0.000000 0.370000 ( 0.370000)
[str] 0.191000 0.000000 0.191000 ( 0.191000)
[num] 0.030000 0.000000 0.030000 ( 0.030000)
Array.new(str) 0.080000 0.000000 0.080000 ( 0.080000)
Array.new(num) 0.060000 0.000000 0.060000 ( 0.060000)
Array.new(hash) 0.100000 0.000000 0.100000 ( 0.100000)
Add 100.000:
+= ['.'] 143.074000 0.000000 143.074000 (143.074000)
+= [0] 126.099000 0.000000 126.099000 (126.099000)
<< ['.'] 0.211000 0.000000 0.211000 ( 0.211000)
<< [0] 0.090000 0.000000 0.090000 ( 0.090000)
a = a+['.'] 124.536000 0.000000 124.536000 (124.536000)
a = a+[0] 127.672000 0.000000 127.672000 (127.672000)
Concatenate 100.000:
[num]+ 0.120000 0.000000 0.120000 ( 0.120000)
[str]+ 0.180000 0.000000 0.180000 ( 0.180000)
[mix]+ 0.120000 0.000000 0.120000 ( 0.120000)
[num]<< 0.070000 0.000000 0.070000 ( 0.070000)
[str]<< 0.211000 0.000000 0.211000 ( 0.211000)
[mix]<< 0.110000 0.000000 0.110000 ( 0.110000)
[num].concat 0.100000 0.000000 0.100000 ( 0.100000)
[str].concat 0.160000 0.000000 0.160000 ( 0.160000)
[mix].concat 0.131000 0.000000 0.131000 ( 0.131000)
union [num] 0.280000 0.000000 0.280000 ( 0.280000)
union [str] 0.300000 0.000000 0.300000 ( 0.300000)
Read 1.000.000:
each: 9.364000 0.000000 9.364000 ( 9.364000)
map: 11.007000 0.000000 11.007000 ( 11.007000)
Other 10.000:
.compact: 0.411000 0.000000 0.411000 ( 0.411000)
.delete(nil): 2.904000 0.000000 2.904000 ( 2.904000)
delete: 4.687000 0.000000 4.687000 ( 4.687000)
--------------------
Total: 553.109000 0.000000 553.109000 (553.069000)
IronRuby
C:ProgettiRubybench>ir bench_arr.rb
user system total real
Create 100.000:
%w() 0.721037 0.000000 0.721037 ( 0.721080)
%w'' 0.230331 0.000000 0.230331 ( 0.250375)
split 1.482131 0.000000 1.482131 ( 1.482220)
[str] 0.240346 0.000000 0.240346 ( 0.240360)
[num] 0.100144 0.000000 0.100144 ( 0.100150)
Array.new(str) 0.150216 0.000000 0.150216 ( 0.150225)
Array.new(num) 0.130187 0.000000 0.130187 ( 0.130195)
Array.new(hash) 0.110158 0.000000 0.110158 ( 0.120180)
Add 100.000:
+= ['.'] 93.234064 9.723982 102.958046 (105.808475)
+= [0] 44.143475 3.294738 47.438213 ( 48.092030)
<< ['.'] 0.160230 0.000000 0.160230 ( 0.160240)
<< [0] 0.090130 0.010014 0.100144 ( 0.100150)
a = a+['.'] 96.779162 9.483637 106.262798 (109.644220)
a = a+[0] 43.823014 3.545098 47.368112 ( 47.921775)
Concatenate 100.000:
[num]+ 0.160230 0.000000 0.160230 ( 0.160240)
[str]+ 0.230331 0.000000 0.230331 ( 0.240360)
[mix]+ 0.180259 0.000000 0.180259 ( 0.180270)
[num]<< 0.090130 0.000000 0.090130 ( 0.090135)
[str]<< 0.180259 0.010014 0.190274 ( 0.190285)
[mix]<< 0.150216 0.000000 0.150216 ( 0.150225)
[num].concat 0.110158 0.010014 0.120173 ( 0.120180)
[str].concat 0.220317 0.000000 0.220317 ( 0.220330)
[mix].concat 0.180259 0.000000 0.180259 ( 0.180270)
union [num] 0.330475 0.000000 0.330475 ( 0.340510)
union [str] 0.410590 0.000000 0.410590 ( 0.410615)
Read 1.000.000:
each: 14.040189 0.010014 14.050203 ( 14.181240)
map: 19.848541 0.020029 19.868570 ( 20.120135)
Other 10.000:
.compact: 1.161670 0.000000 1.161670 ( 1.171755)
.delete(nil): 15.462234 0.030043 15.492277 ( 15.833715)
delete: 1.422045 0.000000 1.422045 ( 1.472205)
--------------------
Total: 335.572530 26.137584 361.710114 (369.984144)
Riepilogo totali:
Ruby 1.8.6
Total: 153.831000 33.478000 187.309000 (191.186350)
Ruby 1.9.1
Total: 109.717000 31.815000 141.532000 (144.306135)
Jruby
Total: 553.109000 0.000000 553.109000 (553.069000)
Ironruby
Total: 335.572530 26.137584 361.710114 (369.984144)
Commento: Dunque, in questo terzo test è importante spendere qualche parola. Il tempo alto di jruby ed ironruby è dovuto anche al fatto che ho voluto comparare la concatenazione += ed una versione simile, entrambi MOLTO sconvenienti per questi due interpreti, i tempi sono infatti altissimi, basterebbe utilizzare solo l'operatore << per avere risultati molto diversi, in ordine: 1.8.6=61 1.9.1=40 jruby=33 e ironruby=60 ...jruby risulterebbe il più veloce.
Un altra curiosità è l'utilizzo del metodo compact, oltre ad essere più elegante è anche più prestazionale del sistema analogo delete(nil) è anche più prestazionale con sensibili differenze in Ironruby.
Gli Hash
Lo script per testare gli Hash è il più pesante nell'utilizzo della memoria, sinceramente non era nelle mie intenzioni ma poi ho pensato di tenerlo così per esaminarne gli esiti:
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 58 59 60 61 | require "benchmark" include Benchmark n=1_000_000 Benchmark.bm(21, "Total:") do|b| puts "Write 1.000.000:" h = {} t1 = b.report("int => str:") do n.times {|x| h[x] = "." } end h = {} t1 += b.report("int => int:") do n.times {|x| h[x] = x } end t1 += b.report("int => [int]:") do n.times {|x| h[x] = [x] } end t1 += b.report(".to_sym => .to_s:") do n.times {|x| h[x.to_s.to_sym] = x.to_s } end puts ":sym => str 1.000.000:" t2 = b.report("Each:") do h.each {|k,v| k; v} end t2 += b.report("each_key:") do h.each_key {|k| k} end t2 += b.report("each_value:") do h.each_value {|v| v} end t2 += b.report("read by key:") do h.each {|k,v| h[k]} end h1=h t3 = b.report("5 invert:") do 5.times { h.invert } end h=h1 t3 += b.report("1000 shift:") do 1000.times { h.shift } end h=h1 t3 += b.report("1000 delete:") do 1000.times {|x| h.delete(x) } end h=h1 t3 += b.report("all delete:") do h.each_key {|k| h.delete(k)} end [t1+t2+t3] end |
Ruby 1.8.6
C:ProgettiRubybench>ruby bench_hsh.rb
user system total real
Write 1.000.000:
int => str: 0.851000 0.030000 0.881000 ( 0.881320)
int => int: 1.021000 0.090000 1.111000 ( 1.141710)
int => [int]: 0.791000 0.030000 0.821000 ( 0.841260)
.to_sym => .to_s: 6.400000 0.080000 6.480000 ( 6.509750)
:sym => str 1.000.000:
Each: 2.553000 0.090000 2.643000 ( 2.684020)
each_key: 0.481000 0.000000 0.481000 ( 0.490735)
each_value: 0.491000 0.000000 0.491000 ( 0.490735)
read by key: 2.854000 0.040000 2.894000 ( 2.904350)
5 invert: 31.185000 0.791000 31.976000 ( 32.438585)
1000 shift: 37.604000 0.010000 37.614000 ( 38.177180)
1000 delete: 0.000000 0.000000 0.000000 ( 0.000000)
all delete: 1.442000 0.010000 1.452000 ( 1.452175)
Total: 85.673000 1.171000 86.844000 ( 88.011820)
Ruby 1.9.1
C:ProgettiRubybench>ruby bench_hsh.rb
user system total real
Write 1.000.000:
int => str: 0.721000 0.100000 0.821000 ( 0.841260)
int => int: 0.590000 0.140000 0.730000 ( 0.731095)
int => [int]: 0.391000 0.020000 0.411000 ( 0.440660)
.to_sym => .to_s: 4.957000 0.320000 5.277000 ( 5.327980)
:sym => str 1.000.000:
Each: 0.691000 0.050000 0.741000 ( 0.801200)
each_key: 0.461000 0.000000 0.461000 ( 0.470705)
each_value: 0.500000 0.000000 0.500000 ( 0.520780)
read by key: 1.022000 0.011000 1.033000 ( 1.051575)
5 invert: 33.939000 1.071000 35.010000 ( 35.603325)
1000 shift: 48.800000 0.020000 48.820000 ( 49.474100)
1000 delete: 0.000000 0.000000 0.000000 ( 0.000000)
all delete: 1.432000 0.010000 1.442000 ( 1.472205)
Total: 93.504000 1.742000 95.246000 ( 96.734885)
JRuby
C:ProgettiRubybench>jruby bench_hsh.rb
user system total real
Write 1.000.000:
int => str: 2.113000 0.000000 2.113000 ( 1.933000)
int => int: 0.721000 0.000000 0.721000 ( 0.721000)
int => [int]: 1.022000 0.000000 1.022000 ( 1.022000)
.to_sym => .to_s: 34.641000 0.000000 34.641000 ( 34.641000)
:sym => str 1.000.000:
Each: 0.541000 0.000000 0.541000 ( 0.541000)
each_key: 0.191000 0.000000 0.191000 ( 0.191000)
each_value: 0.240000 0.000000 0.240000 ( 0.240000)
read by key: 0.761000 0.000000 0.761000 ( 0.761000)
5 invert: Error: Your application used more memory than the safety cap.
IronRuby
C:ProgettiRubybench>ir bench_hsh.rb
user system total real
Write 1.000.000:
int => str: 2.183139 0.030043 2.213182 ( 2.213315)
int => int: 1.211742 0.030043 1.241786 ( 1.291935)
int => [int]: 1.712462 0.010014 1.722477 ( 1.732595)
.to_sym => .to_s: 7.460728 0.120173 7.580901 ( 7.781655)
:sym => str 1.000.000:
Each: 1.111598 0.000000 1.111598 ( 1.131695)
each_key: 0.340490 0.000000 0.340490 ( 0.350525)
each_value: 0.330475 0.010014 0.340490 ( 0.350525)
read by key: 1.021469 0.000000 1.021469 ( 1.031545)
5 invert: 5.588035 0.350504 5.938539 ( 7.381055)
1000 shift: 0.020029 0.000000 0.020029 ( 0.190285)
1000 delete: 0.020029 0.000000 0.020029 ( 0.080120)
all delete: 1.031483 0.020029 1.051512 ( 1.061590)
Total: 22.031680 0.570821 22.602501 ( 24.596839)
Riepilogo totali:
Ruby 1.8.6
Total: 85.673000 1.171000 86.844000 ( 88.011820)
Ruby 1.9.1
Total: 93.504000 1.742000 95.246000 ( 96.734885)
Jruby
*** Out of memory ***
Ironruby
Total: 22.031680 0.570821 22.602501 ( 24.596839)
Commento: JRuby non ha concluso per un errore di out of memory, il processo java è arrivato ad occupare 600Mb nel test dove si effettua un'inversione degli hash, raggiungendo il limite della JVM. Il meno ingordo di memoria è stato ruby 1.8.6 con "soli" 300Mb mentre la 1.9.1 era quasi fisso su 530Mb, non aumentava, come se ci fosse un muro. Non c'era invece per Ironruby che ha superato la barriera dei 600Mb ma con risultati soprendenti, il test dell'inversione in 5 secondi, contro 33 della 1.9.1!
Rieseguengo il test con 2Gb di ram:
Ruby 1.8.6
C:ProgettiRubybench>ruby bench_hsh.rb
user system total real
Write 1.000.000:
int => str: 0.811000 0.060000 0.871000 ( 0.871252)
int => int: 1.081000 0.050000 1.131000 ( 1.141642)
int => [int]: 0.751000 0.030000 0.781000 ( 0.801152)
.to_sym => .to_s: 6.299000 0.130000 6.429000 ( 6.469302)
:sym => str 1.000.000:
Each: 2.474000 0.060000 2.534000 ( 2.553672)
each_key: 0.491000 0.000000 0.491000 ( 0.490706)
each_value: 0.500000 0.000000 0.500000 ( 0.500720)
read by key: 2.834000 0.080000 2.914000 ( 2.964263)
5 invert: 30.454000 0.992000 31.446000 ( 31.885849)
1000 shift: 38.285000 0.020000 38.305000 ( 38.765743)
1000 delete: 0.000000 0.000000 0.000000 ( 0.000000)
all delete: 1.472000 0.010000 1.482000 ( 1.512174)
Total: 85.452000 1.432000 86.884000 ( 87.956475)
Ruby 1.9.1
C:ProgettiRubybench>ruby bench_hsh.rb
user system total real
Write 1.000.000:
int => str: 0.701000 0.090000 0.791000 ( 0.790640)
int => int: 0.661000 0.100000 0.761000 ( 0.780631)
int => [int]: 0.360000 0.020000 0.380000 ( 0.390316)
.to_sym => .to_s: 4.947000 0.380000 5.327000 ( 5.524472)
:sym => str 1.000.000:
Each: 0.631000 0.041000 0.672000 ( 0.690558)
each_key: 0.451000 0.000000 0.451000 ( 0.450365)
each_value: 0.490000 0.000000 0.490000 ( 0.490397)
read by key: 0.892000 0.030000 0.922000 ( 0.940761)
5 invert: 27.760000 6.299000 34.059000 ( 34.547961)
1000 shift: 48.289000 0.020000 48.309000 ( 48.789488)
1000 delete: 0.000000 0.000000 0.000000 ( 0.000000)
all delete: 1.072000 0.370000 1.442000 ( 1.441166)
Total: 86.254000 7.350000 93.604000 ( 94.836755)
JRuby
C:ProgettiRubybench>jruby bench_hsh.rb
user system total real
Write 1.000.000:
int => str: 2.261000 0.000000 2.261000 ( 2.081000)
int => int: 0.760000 0.000000 0.760000 ( 0.760000)
int => [int]: 1.051000 0.000000 1.051000 ( 1.051000)
.to_sym => .to_s: 35.694000 0.000000 35.694000 ( 35.694000)
:sym => str 1.000.000:
Each: 0.481000 0.000000 0.481000 ( 0.481000)
each_key: 0.190000 0.000000 0.190000 ( 0.190000)
each_value: 0.190000 0.000000 0.190000 ( 0.190000)
read by key: 0.701000 0.000000 0.701000 ( 0.701000)
5 invert: Error: Your application used more memory than the safety cap.
C:ProgettiRubybench>jruby bench_hsh.rb -J-Xmx1500m
user system total real
Write 1.000.000:
int => str: 1.612000 0.000000 1.612000 ( 1.562000)
int => int: 0.842000 0.000000 0.842000 ( 0.842000)
int => [int]: 1.101000 0.000000 1.101000 ( 1.101000)
.to_sym => .to_s: 35.341000 0.000000 35.341000 ( 35.341000)
:sym => str 1.000.000:
Each: 0.431000 0.000000 0.431000 ( 0.431000)
each_key: 0.180000 0.000000 0.180000 ( 0.180000)
each_value: 0.190000 0.000000 0.190000 ( 0.200000)
read by key: 0.701000 0.000000 0.701000 ( 0.691000)
5 invert: 11.076000 0.000000 11.076000 ( 11.076000)
1000 shift: 0.000000 0.000000 0.000000 ( 0.000000)
1000 delete: 0.000000 0.000000 0.000000 ( 0.000000)
all delete: 0.912000 0.000000 0.912000 ( 0.912000)
Total: 52.385999 0.000000 52.385999 ( 52.335999)
IronRuby
C:ProgettiRubybench>ir bench_hsh.rb
user system total real
Write 1.000.000:
int => str: 2.283283 0.090130 2.373413 ( 2.363398)
int => int: 1.201728 0.030043 1.231771 ( 1.241786)
int => [int]: 1.792578 0.020029 1.812606 ( 1.862678)
.to_sym => .to_s: 7.340555 0.120173 7.460728 ( 7.590915)
:sym => str 1.000.000:
Each: 1.091570 0.000000 1.091570 ( 1.141642)
each_key: 0.310446 0.000000 0.310446 ( 0.310447)
each_value: 0.360518 0.000000 0.360518 ( 0.360518)
read by key: 1.001440 0.000000 1.001440 ( 1.001440)
5 invert: 4.816926 0.070101 4.887027 ( 4.917070)
1000 shift: 0.010014 0.000000 0.010014 ( 0.010014)
1000 delete: 0.010014 0.000000 0.010014 ( 0.010015)
all delete: 1.061526 0.000000 1.061526 ( 1.071541)
Total: 21.280600 0.330475 21.611075 ( 21.881464)
Riepilogo totali:
Ruby 1.8.6
Total: 85.452000 1.432000 86.884000 ( 87.956475)
Ruby 1.9.1
Total: 86.254000 7.350000 93.604000 ( 94.836755)
Jruby
Total: 52.385999 0.000000 52.385999 ( 52.335999)
Ironruby
Total: 21.280600 0.330475 21.611075 ( 21.881464)
Commento: JRuby si blocca al solito test e sempre con un processo di 600Mb, ho quindi alzato il cap di memoria a 1,5Gb e gli ha permesso di concludere ed anche con un buon tempo ma il processo ha raggiunto dimensioni mostruose, ha di poco superato il giga. Ruby 1.8.6 sempre il meno esoso con 300Mb e la 1.9.1 sempre 530Mb. Entrambi hanno tempi alti con l'inversione ed in particolare con il metodo shift al contrario degli altri due. Ironruby ancora il più veloce con un processo che si accorge della maggiore quantità di memoria e ne usa un altro pò arrivando ad allocare quasi 700Mb.
Le delete degli elementi è sempre stata velocissima anche se aumentavo il numero, forse non ho controllato bene che non venisse effettuata in un unica chiamata, comunque mi accontento di questo risultato.
Conclusioni:
Ogni interprete ha i propri ambiti dove eccelle, Ironruby quando lo fa, lo fa bene distanziando gli altri. Anche JRuby si è preso i suoi trionfi, forse avevo un pò più aspettative dalla versione 1.9.1 anche se credo non sia un suo demerito bensì sono stati gli altri a migliorare molto negli ultimi mesi. La versione 1.8.6 mi ha ben impressionato in questa sua nuova versione o meglio patch 368, è migliorata molto accorciando le distanze prestazionali con la nuova 1.9, pur non avendo una VM. Inoltre è la versione più equilibrata senza alti nè bassi e c'è da considerare che è ancora la versione più usata, più compatibile e con il maggior numero di gemme.
Spero che questo articolo sia risultato interessante, nel prossimo includerò un confronto con python 2.6.2 e la nuova versione 3.1.1 che mi risulta essere velocissima, hola!
Paolo
8 August 2009 at 11:07
Mi ha incuriosito la variazione di performance dei metodi di concatenazione di stringhe, che è un’operazione che si fa di continuo. Mi sono chiesto allora quale fosse il metodo più veloce tra tutti.
Ho allora ripetuto il benchmark delle stringhe aggiungendo altri due metodi di concatenzione, ossia
%(#{stringa1} #{stringa2})
e
a = []; a << stringa1; a << stringa2; a.join(" ")
e facendo la prova anche con stringhe lunghe, da 500 caratteri l'una.
Innanzitutto ho notato che ripetendo un po' di volte il test << #{} e %() risultano praticamente identici. Qualche volta vince uno e qualche volta vince un altro.
Per stringhe di un carattere il metodo dell'array è un po' più lento mentre per stringhe lunghe si pareggia agli altri. Per stringhe lunghe + diventa estremamente più lento di tutti gli altri metodi.
Questo è il risultato di un'instanza del test, sperando che la formattazione sopravviva al post.
user system total real
Concat 1.000.000:
+ 2.370000 0.130000 2.500000 ( 2.532409)
<< 2.310000 0.150000 2.460000 ( 2.493730)
#{} 2.410000 0.180000 2.590000 ( 2.582961)
%() 2.420000 0.150000 2.570000 ( 2.588971)
Array 4.250000 0.170000 4.420000 ( 4.445646)
big + 14.360000 0.240000 14.600000 ( 14.635854)
big #{} 6.210000 0.170000 6.380000 ( 6.401311)
big %() 6.330000 0.180000 6.510000 ( 6.522818)
big Array 6.500000 0.440000 6.940000 ( 6.956503)
Portando le stringhe da concatenare da 500 a 1000 caratteri la concatenazione con Array rimane al livello degli altri. A 2000 inizia ad essere leggermente più veloce e a 4000 è decisamente più rapida.
big + 86.840000 0.270000 87.110000 ( 87.336664)
big #{} 30.950000 0.190000 31.140000 ( 31.217629)
big %() 31.100000 0.270000 31.370000 ( 31.472801)
big Array 26.140000 6.470000 32.610000 ( 32.672105)
I test sono stati eseguiti su un Intel Core Duo 2 T7200 (dual core 2.0 GHz), ruby 1.8.7 (2008-08-11 patchlevel 72) [x86_64-linux] 3.4 GB RAM.
Il codice in più è
t1 = b.report("big +") do
sa="%04000d" % 1; sb="%04000d" % 2; sc="%04000d" % 3;
sd="%04000d" % 4; se="%04000d" % 5
n.times { sa + " " + sb + " " + sc + " " + sd + " " + se; sb + " " + sc }
end
t1 += b.report("big \#\{\}") do
sa="%04000d" % 1; sb="%04000d" % 2; sc="%04000d" % 3;
sd="%04000d" % 4; se="%04000d" % 5
n.times { "#{sa} #{sb} #{sc} #{sd} #{se}"; "#{sb} #{sc}" }
end
t1 += b.report("big \%\(\)") do
sa="%04000d" % 1; sb="%04000d" % 2; sc="%04000d" % 3;
sd="%04000d" % 4; se="%04000d" % 5
n.times { %(#{sa} #{sb} #{sc} #{sd} #{se}); %(#{sb} #{sc}) }
end
t1 += b.report("big Array") do
sa="%04000d" % 1; sb="%04000d" % 2; sc="%04000d" % 3;
sd="%04000d" % 4; se="%04000d" % 5
n.times { a = []; a << sa; a << sb; a << sc; a << sd; a << se; a.join(" ");
a = []; a << sb; a << sc; a.join(" ") }
end
Il test big << manca perché l'operatore << modifica il suo argomento di sinistra e non avevo voglia di includere dei literal da 4000 caratteri nel programma.