Ciao!!!
Spero che i fans di guerre stellari non me ne vogliano per la citazione del titolo
Dopo settimane di ritardo e alcune discussioni con Ari (come chi è? … non avete letto i commenti al primo articolo?) sono tornato con ulteriori test e risultati da proporvi.
In realtà questa seconda parte doveva essere diversa, ma viste le giuste osservazioni fatte da Ari ho deciso di cambiarlo per dare ascolto a chi questo blog lo legge e quindi da un senso e uno stimolo a chi qui scrive esclusivamente per passione.
Torniamo a noi! Ari mi ha fatto giustamente notare che le routines di python che leggono i file sono scritte in C. Quindi in realtà non è python che legge velocemente i file, ma il codice C dietro le quinte che fa il lavoro sporco.
Ne è seguita una piccola discussione sulla valenza da dare al mio precedente articolo e su quali sarebbero stati i test giusti da fare… e di seguito troverete i risultati che ho ottenuto ![]()
Ho giocato anche a fare la “Cassandra” di turno (non ditemi che non sapete chi è Cassandra
) per cui vi riporto le mie sibilline parole:
“Per cui nella seconda parte dell’articolo faremo i test che suggerisci, ma ho il sospetto che vedremo dei risultati interessanti, almeno in base a quella che è stata la mia esperienza con Java.”
Ma andiamo a cominciare…
Il test eseguito è molto semplice. Ho fatto calcolare il fattoriale da 1 a 10.000 con una bella procedura non ricorsiva e poi ho fatto un “ottimo” sort con una procedura non efficente (ditemi quanti di voi saprebbero scrivere a memoria un algoritmo di quicksort
)
Vediamo i sorgenti e i risultati ottenuti per python, C, Objective C e Java.
#!/usr/bin/env python2.6
# -*- coding: utf-8 -*-
import time
import array
MAXLOOP = 10000
nArray = array.array('d', range(MAXLOOP))
t0 = time.time()
print "Tempo inizio caricamento array: ", time.strftime("%H:%M:%S")
for i in range(MAXLOOP):
f = float(1)
for a in range(i):
f = f * a
nArray[i] = i + f
t1 = time.time()
print "Tempo fine caricamento array: ", time.strftime("%H:%M:%S")
print "Tempo di caricamento dei dati: ", t1 - t0, " secondi"
t0 = time.time()
print "Tempo inizio ordinamento: ", time.strftime("%H:%M:%S")
# ordinamento in maniera decrescente
for i in range(MAXLOOP):
dMax = nArray[i];
for j in range (i + 1, MAXLOOP):
if nArray[j] > dMax:
dTemp = nArray[j];
nArray[j] = dMax;
nArray[i] = dTemp;
dMax = dTemp;
t1 = time.time()
print "Tempo fine ordinamento: ", time.strftime("%H:%M:%S")
print "Tempo di caricamento dei dati: ", t1 - t0, " secondi"
I tempi sono stati sulla mia macchina freebsd sono stati:
- 11,06 s per il caricamento dell’array con calcolo del fattoriale
- 42,07 s per il sort
Vediamo il C come si comporta:
#include <stdio.h>
#include <time.h>
const int MAXLOOP = 10000;
int main (int argc, const char * argv[])
{
time_t startTime;
time_t endTime;
struct tm * timeinfo;
long double nArray[MAXLOOP];
int i;
time(&startTime);
timeinfo = localtime(&startTime);
printf("Tempo inizio caricamento array: %s", asctime(timeinfo));
for (i = 0; i < MAXLOOP; i++)
{
// Calcolo del fattoriale
long double f = 1;
int a;
for(a = 1; a <= i; a++)
{
f *= a;
}
nArray[i] = i * f;
}
time(&endTime);
timeinfo = localtime(&endTime);
printf("Tempo fine caricamento array: %s", asctime(timeinfo));
time(&startTime);
timeinfo = localtime(&startTime);
printf("Tempo inizio ordinamento: %s", asctime(timeinfo));
// ordinamento in maniera decrescente
for (i = 0; i < MAXLOOP; i++)
{
double dMax = nArray[i];
int j;
for (j = i + 1; j < MAXLOOP; j++)
{
if (nArray[j] > dMax)
{
double dTemp = nArray[j];
nArray[j] = dMax;
nArray[i] = dTemp;
dMax = dTemp;
}
}
}
time(&endTime);
timeinfo = localtime(&endTime);
printf("Tempo fine ordinamento: %s", asctime(timeinfo));
return 0;
}
Tempi:
- 4 s per il caricamento dell’array con calcolo del fattoriale
- meno di 1 s per il sort
Adesso è il turno di objective C.
#import <Foundation/Foundation.h>
const int MAXLOOP = 10000;
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSDate *startTime;
NSDate *endTime;
NSMutableArray *nArray = [[NSMutableArray alloc] initWithCapacity: MAXLOOP];
int i;
startTime = [NSDate date];
NSLog(@"Tempo inizio caricamento array: %@", startTime);
for (i = 0; i < MAXLOOP; i++)
{
// Calcolo del fattoriale
long double f = 1;
int a;
for(a = 1; a <= i; a++)
{
f *= a;
}
[nArray addObject: [NSNumber numberWithDouble: i * f]];
}
endTime = [NSDate date];
NSLog(@"Tempo fine caricamento array: %@", endTime);
startTime = [NSDate date];
NSLog(@"Tempo inizio sort: %@", startTime);
// ordinamento in maniera decrescente
for (i = 0; i < MAXLOOP; i++)
{
double dMax = [[nArray objectAtIndex: i] doubleValue];
int j;
for (j = i + 1; j < MAXLOOP; j++)
{
if ([[nArray objectAtIndex: j] doubleValue] > dMax)
{
double dTemp = [[nArray objectAtIndex: j] doubleValue];
[nArray replaceObjectAtIndex: j withObject: [NSNumber numberWithDouble: dMax]];
[nArray replaceObjectAtIndex: i withObject: [NSNumber numberWithDouble: dTemp]];
dMax = dTemp;
}
}
}
endTime = [NSDate date];
NSLog(@"Tempo fine sort: %@", endTime);
[pool drain];
return 0;
}
Tempi:
- 4 s per il caricamento dell’array con calcolo del fattoriale
- 2,13 s per il sort
Per finire passiamo a Java.
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SortTest {
static final int MAXLOOP = 10000;
public static void main(String[] args) {
// TODO code application logic here
int i;
double[] nArray = new double[MAXLOOP];
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date startTime = new Date();
System.out.printf("Tempo inizio caricamento array: %s\n", dateFormat.format(startTime));
long start = System.nanoTime();
for (i = 0; i < MAXLOOP; i++)
{
// Calcolo del fattoriale
double f = 1;
int a;
for(a = 1; a <= i; a++)
{
f *= a;
}
nArray[i] = i * f;
}
long end = System.nanoTime();
Date endTime = new Date();
System.out.printf("Tempo fine caricamento array: %s\n", dateFormat.format(endTime));
System.out.printf("Tempo caricamento array: %d ms\n", (end - start) / 1000000);
startTime = new Date();
System.out.printf("Tempo inizio ordinamento: %s\n", dateFormat.format(startTime));
start = System.nanoTime();
// ordinamento in maniera decrescente
for (i = 0; i < MAXLOOP; i++)
{
double dMax = nArray[i];
int j;
for (j = i + 1; j < MAXLOOP; j++)
{
if (nArray[j] > dMax)
{
double dTemp = nArray[j];
nArray[j] = dMax;
nArray[i] = dTemp;
dMax = dTemp;
}
}
}
end = System.nanoTime();
endTime = new Date();
System.out.printf("Tempo fine ordinamento: %s\n", dateFormat.format(endTime));
System.out.printf("Tempo ordinamento array: %d ms\n", (end - start) / 1000000);
}
}
Tempi:
- 248 ms per il caricamento dell’array con calcolo del fattoriale
- 278 ms per il sort
Quindi riassumiamo il tutto in un formato più leggibile.
|
Caricamento |
Sort |
|
|
Python |
11,06 s |
42,07 s |
|
C |
4 s |
< 1 s |
|
Objective-C |
4 s |
2,13 s |
|
Java |
0,25 s |
0,28 s |
Per cui come diceva Ari, il compilato è più efficente. Possiamo notare la differenza di tempi nel sort tra objective-c e C ma l’array usato in objective-c è un NSMutableArray che vuole oggetti al suo interno, per cui è presente un overhead dovuto alla creazione dell’oggetto… in soldoni non stiamo spostando dei semplici long double come in C.
Infine la sorpresa “cassandriana” di Java… che è un bytecode che viene interpretato da una virtual machine.
Anche python genera del bytecode… evidentemente meno efficente di quello java.
Ma torniamo a noi con le conclusioni di questa seconda parte. Comincio mettendo le mani avanti. Io sono un programamtore “stagionato” o “antico” questo vuol dire che mi piace il codice che funziona velocemente e non mi ammazza un processore con 6 core e GHz di potenza se lancio 2 istanze di un programma. Anche se preferisco il C/C++ o Delphi, non mi faccio trascinare dalle mode e ho capito oramai da anni che il linguaggio “buono” è quello che ti permette di staccare il cliente dalla propria giugulare prima di finire dissanguati
per cui se il mio software deve leggere file, fare sort e usare le regular expression allora python mi permette con poche righe di codice di fare tutto ciò e con poche modifiche di spostarmi su varie piattaforme.
Se invece il problema da risolvere è in ambiente real time o prevede calcoli a go-go o pochissima RAM come in un sistema embedded allora la scelta giusta è il C (provate a far girare python su una centralina di un’auto
). Se volete lavorare su MAC e scrivere PDF e vedere le vostre applicazioni volare passate ad objective-C.
La scusa della battaglia compilati VS interpretati era solo un pretesto per scrivere del codice e sfatare preconcetti e come ho detto in più occasioni non voleva essere un test scientifico che avrebbe richiesto uno rigore diverso.
L’importante è “divertirsi” ed imparare. Senza diventare gli hooligans dei chip. Ciao e alla prossima







Questo comando installerà non solo il compilatore ma anche il framework 

