Compilati VS interpretati passo 1.

Comincio facendo una premessa. Quando si deve sviluppare un progetto informatico non esiste il linguaggio del momento, o preferito, o “più bello”. Esiste un gruppo di lavoro con le sue competenze ed una problematica da risolvere. Le considerazioni che seguono sono basate su dei test che non mirano ad essere esaustivi. Lo scopo di quest’analisi è quello di porre domande e ottenere delle risposte. Per cui chiunque non concordasse con i risultati e fosse in grado di aggiungere nuovi tasselli al mosaico che si sta andando a costruire è ben accetto. Quindi… vado ad incominciare.

Era il 1991 mi venne chiesto di velocizzare un algoritmo che durava su un intel 386 la bellezza di 24 ore. Il software era scritto in quick basic che non brillava certo in performance. La soluzione fu di linkare la routine di calcolo scritta in C al programma quick basic. Magia!!! La procedura di calcolo durava solo più un ora.
Sempre in quegli anni era comune trovare sulle riviste test relativi alle performance dei linguaggi, così si trovavano i tempi di compilazione, quelli di esecuzione di sort, accesso ai dischi in maniera sequenziale e random. Tutte cose utilissime, perché i dischi erano da 20/40 Mb e i processori da 20 MHz e spesso privi di coprocessore matematico non c’era tutto il lusso che abbiamo adesso 🙂

Comunque la regola d’oro era che i programmi compilati sono più veloci di quelli interpretati… adesso però quasi tutti i nuovi linguaggi di programmazione hanno la caratteristica di essere o totalmente interpretati o in pseudo codice. La motivazione è che i processori moderni sopperiscono con la loro velocità al divario di performance tra un programma compilato ed uno interpretato. Ovviamente gli interpretati hanno alcuni vantaggi come la tipizzazione a runtime che possono essere utili nella creazione di framework, inoltre in ambienti WEB dove il collo di bottiglia è la banda passante alcuni tempi diventano trascurabili. Così giusto per curiosità ho deciso di fare un test, assolutamente non esaustivo, ma che mi ha lasciato a bocca aperta (leggete e scoprirete perché).

La mia idea era di vedere i tempi di accesso al disco e di sort in memoria di una “grossa” mole di dati. Mi sono creato un file di 1,29GB (mi sembrava molto grosso) pieno di stringhe ordinate in modo decrescente e ho scritto un programma di lettura e sort in maniera crescente misurando i tempi di esecuzione. Ovviamente sono partito da un bel programma objective-c dicendomi: “è compilato, ha le sue fondamenta nel C, il framework cocoa l’ha scritto Apple, sara una vera bomba” 🙂 vi anticipo che mi è esplosa tra le mani 🙂

Il codice è molto semplice:


#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
 {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSLog(@"Inizio lettura");
    NSString *stringa = [NSString stringWithContentsOfFile:@"NoteTrim.txt" encoding:NSISOLatin1StringEncoding error:nil];
    NSArray *array = [stringa componentsSeparatedByString:@"\n"];
    NSLog(@"Fine lettura");

    NSLog(@"Inizio sort");
    array = [array sortedArrayUsingSelector:@selector(compare:)];
    NSLog(@"Fine sort");

    [pool drain];
    return 0;
}

Ed ecco i risultati:
– objective-c Lettura 32 s
– objective-c Sort 1,5 s

I tempi non mi dicevano un granché per cui ho accettato i 32 s per il caricamento e l’1,5 s per il sort  fiducioso della legge: compilato più veloce dell’interpretato.

Per l’interpretato sono partito usando python, sicuro di un aiuto da parte di Juhan per colmare le mie lacune (l’aiuto c’è stato, oramai vale l’ugualianza Juhan = F1). Il risultato è il sorgente che segue:

#!/usr/bin/ env python
# -*- coding: utf-8 -*-

import time

try:
  # lettura del file
  t0 = time.time()
  print "Tempo inizio: ", time.strftime("%H:%M:%S")
  file_input = open("NoteTrim.txt", "ru")
  lines = file_input.readlines()
  file_input.close()
  t1 = time.time()
  print "Tempo fine: ", time.strftime("%H:%M:%S")
  print "Tempo di caricamento dei dati: ", t1 - t0, "secondi"

  # ordinamento del file
  t0 = time.time()
  print "Tempo inizio: ", time.strftime("%H:%M:%S")
  lines.sort()
  print "Elementi caricati: ", len(lines)
  t1 = time.time()
  print "Tempo fine: ", time.strftime("%H:%M:%S")
  print "Tempo di ordinamento dei dati: ", t1 - t0, "secondi"
except(IOError):
  print "Errore nell'elaborazione del file NoteTrim.txt"
  quit()

Devo dire che ho trovato le istruzioni necessarie in un batter d’occhio e che su internet si trova veramente di tutto riferito a python e questo è sicuramente un vantaggio non indifferente.
Lancio il tutto e… mi cade la mascella per terra! 3,6 s per leggere il file e 0,38 s per il sort. Giuro che mi è caduto in testa un macigno 🙂 e meno male che ho la testa dura!!!

I più accorti mi faranno notare che la lettura di un file dipende molto dal sistema operativo e che quindi avrei risultati diversi a parità di computer ma con S.O. differenti e che il sort di stringhe dipende da come vengono trattate le stringhe sempre a livello di S.O. e di linguaggio, ma il divario è sconcertante!
Per cui decido di approfondire la questione (ci ho impiegato i mesi trascorsi dall’ultimo articolo), molto per curiosità e molto perché la differenza tra compilati e interpretati era un concetto dei tempi delle scuole.
Mi accorgo che la versione di python è la 2.7.1 per cui mi chiedo “chissà che performance ci saranno con la 3.0 così ingenuamente lancio lo stesso sorgente… e chiamo Juhan 🙂 il sorgente che prima funzionava era diventato pieno di errori.

Per uno strano motivo non interpretava correttamente i tab e così ho dovuto ribattere tutto il sorgente. Poi ho scoperto che è cambiata la sintassi della print 😦 adesso ha bisogno delle parentesi e per ultimo nella open dovevo specificare l’encoding dei caratteri altrimenti il tutto non parte. Per cui il nuovo sorgente é diventato:

#!/usr/local/bin/ env pythonw3
# -*- coding: iso-8859-1 -*-

import time

try:
  # lettura del file
  t0 = time.time()
  print("Tempo inizio: ", time.strftime("%H:%M:%S"))
  file_input = open("NoteTrim.txt", "r", encoding='cp1252')
  lines = file_input.readlines()
  file_input.close()
  t1 = time.time()
  print("Tempo fine: ", time.strftime("%H:%M:%S"))
  print("Tempo di caricamento dei dati: ", t1 - t0, "secondi")

  # ordinamento del file
  t0 = time.time()
  print("Tempo inizio: ", time.strftime("%H:%M:%S"))
  lines.sort()
  print("Elementi caricati: ", len(lines))
  t1 = time.time()
  print("Tempo fine: ", time.strftime("%H:%M:%S"))
  print("Tempo di ordinamento dei dati: ", t1 - t0, "secondi")
except(IOError):
  print("Errore nell'elaborazione del file NoteTrim.txt")
  quit()

e i tempi diventano 11,78 s per il caricamento del file e 1,65 per il sort. Le performance erano calate esponenzialmente quasi 4 volte più lento in lettura e nel sort.

Spinto dalla curiosità provo il tutto sotto winzot (non è un errore ma l’incrocio tra windows e lo ZOT dei fumetti di BC) in una macchina virtuale… Primo e unico problema con la 2.7.2 devo modificare la open. Non accetta l’opzione “ru” e devo sostituirla con la sola “r” e i tempi diventano:

– Python 2.7 Lettura 36,66 s
– Python 2.7 Sort 0,88 s

Con la versione 3 non devo fare modifiche e ottengo i seguenti tempi:

– Python 3.2 Lettura 60,70 s
– Python 3.2 Sort 2,58 s

Qui comincio a pormi alcune domande:

– Come mai a parità di S.O. la nuova versione di python è più lenta
– Perché non è stata mantenuta la piena compatibilità tra la 2.7 e la 3.2 visto che in un sorgente di 20 righe ne ho dovute modificare ben 9
– Perché ho delle diversità a livello di S.O. nella scrittura del codice. I parametri della open non vengono accettati a parità di versione.

Sono quei tarli che ti assillano che potrebbero essere lasciati tranquillamente in disparte. Sicuramente i programmi python non sono pieni di print come il mio esempio e sicuramente ci sono state innovazioni in altre parti del linguaggio che non sono ricadute nel mio test… e io non sono un esperto python, ne voglio vantarmi di esserelo. Però bisogna porsi delle domande e non si può lasciare correre tutto, poi arrivando da anni di Turbo Pascal prima e Delphi dopo è la prima volta che ricado in un porting problematico (dove cioè devo modificare un sorgente che non funziona più)… ma questi magari saranno spunti per un nuovo post.

Preso dalla curiosità e invidioso di Juhan che scrive articoli più interessanti dei miei provo anche il newlisp. Quante righe di codice? 4 contando anche la shell.

#!/usr/bin/newlisp

(println "Lettura: " (time (set ‘data (parse (read-file "NoteTrim.txt") "\n" 0))) " ms")
(println "Sort: " (time (sort data)) " ms")

(exit)

Risultati? Impressionanti anche questi. Lettura 4,66 s e sort in 1,7 secondi. Decido di provare la cosa anche sotto windows ma purtroppo durante il caricamento del file ottengo un errore di memoria… indagherò e vi farò sapere.

Quindi riassumiamo:

OSX Lion

Windows 7 64 Bit

Lettura (s)

Sort (s)

Lettura (s)

Sort (s)

Objective-C

32

1,5

Python 2.7

3,6

0,38

36,66

0,88

Python 3.2

11,78

1,65

60,70

2,58

NewLisp

4,66

1,7

A questo punto direi di saltare alle conclusioni di questa prima parte.

– I linguaggi interpretati sono veloci e certe verità del passato vanno riviste.
– I nuovi linguaggi sono compatti e pieni di librerie notevoli, per non dire incredibili (in newlisp solo 4 righe di codice con dei risultati di prima categoria).

A questo punto passiamo tutti a python o al lisp? Ovviamente no. Non tutti i software leggono e sortano file, abbiamo calcoli in virgola mobile, interfacce grafiche, applicazioni real time. Quindi i linguaggi compilati devono essere usati solo per applicazioni specifiche e sono meno performanti? Anche questo non è vero. L’applicativo objective-C si basava sulle librerie ad alto livello, ma la base di objective-C è il C che è tante cose, ma lento proprio no. Per cui è il momento di andare a mettere le mani sotto il cofano e vedere se è possibile migliorare… ma questo lo vedremo nella prossima puntata.

Posta un commento o usa questo indirizzo per il trackback.

Commenti

  • juhan  Il 7 novembre 2011 alle 19:24

    Dikiyvolk hai messo tanta carne al fuoco che risponderti sarà un problema!
    Io verificherò il Python; mi sembra strano che la nuova versione sia meno performante della vecchia, certo sono cambiate delle cose.
    Per newLISP (solo io lo scrivo giusto, cioè così?) bisognerebbe verificare se usa chiamate al O.S. o se è fatto davvero bene; anche perché don Lucio dice che la nuova versione prossima ventura è molto migliorata (staremo a vedere).
    Mancano, secondo me, le versioni in C puro (senza +) e Fortran. Però per quest’ultimo ai miei tempi le funzioni di sort te le scrivevi o usavi quelle di una libreria, da verificare, sono passati 20 anni, chissà se nel frattempo…

    Un’ultima cosa: da qualche anno io vado con script di lunghezza umana, ottimi interpretati. Per i compiti più onerosi mi verrebbe da pensare che la compilazione sia essenziale. Oltre al progetto.

    Mi sa che ne riparleremo.

    • Dikiyvolk  Il 7 novembre 2011 alle 20:58

      Ciao juhan,

      Ne ho scritta una versione in quasi C puro, uso delle chiamate objective-C ma non nel codice principale… mica potevo accontentarmi di quei tempi 🙂 e ne ho scritta anche una in C++ che non è male e senza chiamate strane.

      Però tutto finirà nella parte seconda che entro lunedì prossimo metterò in forma leggibile.

      Mi segno come si scrive newLISP, comunque credo sia un problema di gestione della memoria. Il LISP standard non era molto efficente con la sua garbage collector, sprecava memoria a go-go e winzot non aiuta! Credo che la stessa cosa sia per python.

  • piergiu  Il 7 novembre 2011 alle 20:18

    Mai mi sarei immaginato un risultato del genere! UAU! (cit.juhan)

    Anche se con sto freddo improvviso la mia capacita di digitare velocemente è calata drasticamente, ho voluto provare se gdb ci mette il suo zampino per rallentare il tutto!
    ho provato con un programmino base C, lettura di numeri da file di 12,5Mb e caricarli in array di int ma qualcosa non funge bene con file di grosse dimensioni perchè giustamente mi si genera un errore di segmentazione. e insomma di mio non riesco ad apprezzare le differenze che un gdb può creare in termini di tempo.

    Per mia malsana curiosità, si può provare quello stesso pezzo di codice compilato senza flags per gdb, cioè un “gcc liscio e via” ?
    io ho usato time.h con le relative funzioni time(),difftime() (sono presenti anche li sulla mela?)

    qui il codice che ho usato , per quel che vale -> http://pastebin.com/eHHWXZZt

    a presto, saluti! 🙂

    • Dikiyvolk  Il 7 novembre 2011 alle 21:05

      Ciao piergiu,

      Come dicevo a juhan ho una versione scritta in quasi c puro che pubblicherò entro lunedì prossimo… il sorgente c’è ma il testo latita 😦
      Adesso ho una riunione dell’asilo di mia figlia, ma domani butterò un occhio sul tuo codice.
      Direi che chi ha scritto le librerie di python è molto bravo 🙂 bisognerebbe scoprire le scelte fatte per la nuova versione 3.0.
      Ho letto il tuo articolo su Scratch… ma mia figlia è ancora troppo piccola ha solo quasi 4 anni anche se gioca ad Hangry bird 🙂

      Scappo che come tutti i programmatori sono già in ritardo!!!

  • glipari  Il 7 novembre 2011 alle 21:30

    Carissimo, hai messo il naso in un casino incredibile: la performance analysis! Tomi e tomi possono essere scritti al riguardo.
    Purtroppo non conosco Objective C, quindi posso dirti poco di pratico. Alcune note al volo:

    1) la gestione della memoria è fondamentale, ed è secondo me l’elemento dirimente qui. In particolare, sarebbe carino spiegare cosa fa di preciso la alloc di objective C.
    2) sempre nell’Objective C, bisognerebbe capire come fa il sort a scambiare due elementi dell’array; se scambia solo i puntatori alle stringhe, è un lampo. Se scambia le stringhe, ci mette anche 10 volte tanto. Visti i tempi, in questo caso propendo per la copia delle stringhe…
    3) Anche per il python direi la stessa cosa: deve essere cambiata la gestione della memoria e il garbage collector tra le due versioni, da qui le differenze. Un’altra sospettata è la funzione sort, sempre per la ragione di prima, anche se la differenza dovrebbe essere maggiore.
    4) evidentemente il newLISP ha un ottimo gestore della memoria!
    5) Attraverso macchina virtuale si vede poco, specialmente se ci sono di mezzo letture dal disco. Se puoi, cerca di rieseguire su un SO senza VM.
    6) open() è una funzione di libreria, non di SO. In particolare, la open del SO non ha modo di distingure file di testo da file binari (almeno gli SO compliant con POSIX come Linux); questa distinzione si ha solo a livello di fopen(), che è funzione di libreria ANSI C. Quindi, la u o U servono solo per la libreria python che le implementa a partire da funzioni di base dell’SO, e il SO appunto non ne sa nulla.

    Domandina: quante misure hai preso per ogni prova? Aspetto con ansia la prossima puntata!

    • Dikiyvolk  Il 8 novembre 2011 alle 00:27

      Chi l’avrebbe mai detto che avrei sollevato un vespaio… ma orami il dado è tratto!!
      Vista l’ora sarò brevissimo. newLisp in ambiente unix è veramente potente da quello che ho potuto vedere e mi ricordo che in passato la sua gestione della memoria era tra quelle scadenti.

      Mi aspettavo la domanda sul numero di volte delle misure… ho fatto pochissime misurazioni, 3 per ogni caso perché ogni volta dovevo riavviare il computer, altrimenti il file finiva nella cache del mio controller raid e i tempi diventavano irrilevanti. Objective-c mi dava gli stessi risultati di python… 🙂

  • Ari  Il 23 novembre 2011 alle 15:15

    Abbi pazienza, ma la stragrande maggioranza del tempo speso da entrambi i programmi è nell’invocazione di due comandi:
    stringWithContentsOfFile + sortedArrayUsingSelector per l’ObjectiveC e file_input.readlines() + lines.sort per il Python.

    Nello specifico, le ultime due sono funzioni NON scritte in Python, ma del set di istruzioni di Python, quindi scritte in C. Ti sei limitato ad invocarle con Python.

    Per cui, hai confrontato le performance delle due implementazioni dei due comandi, che sono entrambi compilati. Voglio dire: quello che hai scoperto è che il sort di Python (riepeto: scritto in C!) è evidentemente più performante del sort scritto per ObjectiveC.

    Diverso caso sarebbe stato se avessi scritto un algoritmo di sorting in Python e uno in ObjectiveC (esperimento che potrebbe essere interessante).

    Di conseguenza, puoi dedurre solo che le funzioni standard di sort e di lettura da disco di ObjectiveC siano molto meno performanti delle rispettive funzioni standard (in C!) di Python, ma non puoi sostenere, con quei due programmi, che l’esecuzione di un algoritmo Python sia più veloce dell’equivalente ObjectiveC.

    Potrei scoprire che lo stesso software in Bash, richiamando cat e sort (anch’essi scritti in C) sia più veloce ancora. O estremamente più lenta. Chissà.

    Ti faccio notare un’altra inesattezza: Python non è affatto un linguaggio di scripting, dal momento che “the mainstream Python implementation, known as CPython, is written in C meeting the C89 standard.[64] CPython compiles Python programs into intermediate bytecode”.
    Python compila in bytecode eseguibile su VM, quindi è compilato esattamente come è compilato il Java. C compila in codice macchina; Python e Java compilano in byte-code, PHP non compila.

    Se vuoi fare un confronto tra linguaggi compilati e linguaggi di script

    1. Scegli un vero linguaggio di script e non un byte-code
    2. Confronta algoritmi implementati in quei linguaggi, non limitarti a invocare con quei linguaggi funzioni di sistema che siano compilate.

    • dikiyvolk  Il 23 novembre 2011 alle 16:03

      Ciao,

      Prima di tutto, grazie per le tue osservazioni.

      Certo UNIX è scritto in C, Windows anche e credo un sacco di programmi che usiamo quotidianamente. Sono scritte quasi sicuramente in C la maggiorparte delle librerie usate dai linguaggi interpretati (a livello di linguaggio, non intendo framework tipo Django per rimanere in ambito python).
      Però quello che il programmatore usa è il linguaggio ad alto livello. Un programmatore objective-C userà le funzioni del framework cocoa (nell’esempio è stato usato un oggetto di tipo NSArray) e uno python userà una lista. Se un’implementazione è migliore il risultato del programma renderà maggiormente felice l’utilizzatore e lo sviluppatore. E alla fine quello che conta sono i risultati…
      E’ infatti significativo che python 3 sia più lento 🙂 perché gestisce le stringhe unicode, credo che l’implementazione delle due funzioni C da te riportate non sia cambiata molto nelle due versioni a livello di algoritmo (di struttura dati si, infatti tale Wirth scrisse non a caso ALGORITMI + STRUTTURE DATI = PROGRAMMI).

      Invece non ho trovato nel mio testo alcun riferimento a python come linguaggio di script, a cosa ti riferisci?
      Il titolo era chiaramente compilati VS interpretati, però è vero che fare l’abbinamento con un linguaggio di scripting usando python o NewLisp per semplici programmini (a mo di bash) è una superficialità comprensibile.

      Il mio esempio non voleva essere un testo accademico, ma far riflettere sulle differenze dovute alle scelta di un linguaggio rispetto ad un altro e dello stesso sistema operativo su cui il programma viene lanciato in esecuzione.

      • Ari  Il 23 novembre 2011 alle 17:06

        Appunto: **Python non è interpretato**.

        È un linguaggio basato su byte-code, come Java. O intendi dire che Java è interpretato?

        Anche se Python fosse interpretato, i tuoi due programmi non sarebbero comunque significativi nel confronto compiled vs interpreted perché, di fatto, l’esecuzione delle istruzioni “interpretate” nell’esempio Python occupa una frazione misera del tempo di esecuzione totale, che è a completo carico dell’esecuzione di funzioni di sistema.

        Questi sono benchmark più fondati, perché basati sull’esecuzione di algorimti significativi, non di invocazione di metodi implementati in altri linguaggi che facciano il 99% del lavoro dell’intero programma

        http://shootout.alioth.debian.org/u32/benchmark.php?test=all&lang=python3&lang2=gpp
        (purtroppo non c’è l’ObjectiveC)

        Cheers

      • dikiyvolk  Il 23 novembre 2011 alle 17:45

        Diciamo che se prendo un programma c per linux non funzionerà su windows e che una virtual machine interpreta il byte code per farlo funzionare sul sistema host. Per cui più ottimizzata è la virtual machine più veloce sarà il codice eseguito, molti anni fa la JAVA virtual machine di IBM era preferibile a quella SUN su linux. Se lancio un “byte-code” python vedrò girare un processo python e chissà cosa starà facendo per tutta l’esecuzione del mio programma? 🙂

        Non sono però sicuro che python risolva il tutto con una semplice chiamata ad una funziona di sistema operativo, come farebbe a spostare le stringhe nella lista (tipo di dato python) il S.O.? E il sort è sempre su un oggetto python e non a livello di file system…
        Però guarderò i link che mi hai mandato appena possibile e nel prossimo post riporterò le tue osservazioni.

        E quindi… degli script chi ne parlava? 😉

      • Ari  Il 23 novembre 2011 alle 18:04

        No, Python non risolve con una chiamata al sistema operativo: risolve chiamando un metodo interno scritto in C.
        Se la cosa ancora non ti convince, eccone il codice sorgente:
        http://svn.python.org/view/python/trunk/Objects/listobject.c?revision=69227&view=markup

        Dietro quella chiamata ci sono 3017 linee di codice C. Per forza che va veloce!

        PS. Perché scrivi byte-code tra virgolette? Python è compilato in vero e proprio bytecode http://docs.python.org/glossary.html#term-bytecode

      • Ari  Il 23 novembre 2011 alle 18:13

        In sostanza quello che dico è che il programma usato per fare il confronto tra ObjectiveC e Python sta usando 27 righe di Python e 3017 righe di C. E il 99% del tempo è speso su quelle 3017 righe, che fanno il grosso del lavoro (se non sostanzialmente tutto)

        Non dico che non indichi nulla, eh! Dico solo che rilava che Python sia estremamente efficiente e ben scritto; ma *NON* che i programmi scritti in Python siano più efficienti di quello ObjectiveC per una differenza interpretato-compilato.
        Si riprovi a scrivere un qualsiasi algoritmo che spenda la maggior parte del tempo su Python (un algoritmo di sorting è l’ideale) e poi si possono discutere i risultati.

      • dikiyvolk  Il 24 novembre 2011 alle 09:02

        Ciao Ari,

        Il discorso se approfondito non è ne semplice come l’ho impostato io, ne semplice come lo vorresti mettere tu. Il codice che tu mi hai mandato è quello che sta dietro l’oggetto list di python. Mi sembra naturale che sia scritto in un linguaggio tipo il C. Un processore capisce solo l’assembly e per noi uomini scrivere tutto a blocchi di 00 0A… non è proprio il massimo. Per cui quando chiamiamo la fopen del C troveremo dietro un insieme di istruzioni, che semplificano la vita a chi scrive i programmi. Il C è scritto in C visto che il C si compila, ma python non può generare codice macchina, quindi “l’interprete” e le librerie che si interfacciano al sistema operativo devono essere scritte in qualche cosa d’altro. Per cui quando io alloco un mio oggetto python di tipo list faccio delle chiamate al S.O. richiedendo la memoria necessaria (è il S.O. che controlla i dischi e la memoria). Mettiamo che io voglia fare un test di allocazione della memoria. Dovrei considerarlo valido oppure no. I secondi spesi ad allocare 1.000.000 di oggetti list sarebbero velocità di python o del codice C che permette l’esecuzione del codice stesso?
        Ma ancora se io facessi un algoritmo di ordinamento altamente inefficente il tempo di accesso agli elementi della lista (quella python) dovrebbe essere conteggiato come python o C.
        Come ho detto il mio non voleva essere un testo scientifico, ma l’obiettivo era rimanere molto sul pratico. Non ho conteggiato i millisecondi con attendibilità galileiana. Lo scopo era testare dei linguaggi in usi comuni. Per cui cosa c’è di più comune che leggere un file e ordinare dei dati? Il programmatore objective-c nello sviluppo userebbe la stringWithContentsOfFile, farebbe i test con un file di 5 righe… e poi si troverebbe il cliente attaccato alla giugulare perché il suo file di 2GB viene letto in 2 minuti e lui voleva 2 sec… 🙂 Per cui ho usato le funzioni standard per un primo test (infatti l’articolo è la prima parte).
        In soldoni il mio scopo era fare un test che rimanesse con i piedi per terra, che desse delle risposte o almeno facesse pensare.
        Anche dire che python è scritto molto bene è un’affermazone che andrebbe ponderata. Posso dirti che su una motherboard con processore ARM un mio collega aveva scritto un programma per leggere dei dati da una seriale in python. Con il programma python il sistema linux su processore ARM si inchiodava ogni 2 o 3 giorni, riscrivendo lo stesso programma in C il S.O. non si pianta più… e negli stress test effettuati è 25 volte più veloce.

        Per rispondere alle altre tue domande… ho scritto “byte-code” tra virgolette, non per delegittimare il byte-code di python, ma perché il concetto stesso di byte-code mi suona divertente. Un tempo gwbasic interpretava il codice… istruzione per istruzione, adesso l’interprete… interpreta il byte-code. Questo non toglie niente alle varie virtual machine e linguaggi, però puoi notare anche tu che ultimamente si usano un sacco di paroloni per riprndere concetti non noti… ma matusalemmici 🙂 tipo “l’application server garantisce la persistenza del dato”, da leggere come “L’application server salva i dati da qualche parte (db, file di testo) altrimenti se si spegne tutto abbiamo fatto una frittata” 🙂 Oppure “ho fatto il deploy dell’applicativo” da leggere come “ho messo l’applicativo in produzione o test, comunque l’ho tolto dal mio computer locale”.

        Per ultimo mi chiedevi perché parlavo di chiamate al S.O. il codice python è più veloce su *nix perché nella lettura file probabilmente usa una chiamata a mmap che non esiste sotto windows, per cui a parità di versione python e sorgente i tempi potrebbero variare significativamente.

  • Ari  Il 25 novembre 2011 alle 09:47

    > Per cui cosa c’è di più comune che leggere un file e ordinare dei dati?

    Sostieni quindi che, avendo scelto un caso molto comune, otterresti risultati simili anche con altri tipi di programma?

    Mi stupisco che non tu riesca a capire il mio messaggio: sostanzialmente è come se tu avessi scritto due sorgenti che affidano il proprio lavoro a librerie esterne; hai collaudato le librerie esterne, non l’esecuzione dei programmi.

    Ti propongo un piccolo test: ripeti le tue misure con questi esempi (sono tutti programmi molto semplici da realizzare):

    – come dal tuo esempio: leggi da un file di testo, poi per ogni riga istanzia un oggetto che riceva nel costruttore la riga di testo letta e la memorizzi in un field interno
    – il classico esempio ricorsivo per il calcolo del fattoriale
    – la visita di un albero (http://it.wikipedia.org/wiki/Depth-first_search#Implementazione_in_Python)
    – calcolo della media di un array di float

    Se hai modo, facci sapere i risultati. Sarei molto curioso (magari confermi la tua scoperta: allora sì che sarebbe una grossa news!)

    • Walter Procopio  Il 25 novembre 2011 alle 11:17

      Riporto le mie parole per intero visto che estrapolare una frase da un contesto crea il rischio di farle cambiare di significato.

      > Lo scopo era testare dei linguaggi in usi comuni.
      > Per cui cosa c’è di più comune che leggere un file e ordinare dei dati?
      > Il programmatore objective-c nello sviluppo userebbe la stringWithContentsOfFile, farebbe i test con un file di 5 righe… e poi si troverebbe il cliente attaccato alla giugulare perché il suo file di 2GB viene letto in 2 minuti e lui voleva 2 sec… 🙂
      > Per cui ho usato le funzioni standard per un primo test (infatti l’articolo è la prima parte).

      Per cui la risposta alla tua domanda:

      > Sostieni quindi che, avendo scelto un caso molto comune, otterresti risultati simili anche con altri tipi di programma?

      E’ già data… quanti hanno la necessità di calcolare la media di un array di float o di eseguire il calcolo fattoriale? Inoltre a questo punto si dovrebbe andare a disquisira anche sulla precisione di lettura dei tempi. Siamo sicuri che i millisecondi siano veramente tali?
      Infatti ho anche scritto nella mia precedente risposta:

      > Come ho detto il mio non voleva essere un testo scientifico, ma l’obiettivo era rimanere molto sul pratico. Non ho conteggiato i millisecondi con attendibilità galileiana.

      e nell’articolo la premessa è stata:

      > Quando si deve sviluppare un progetto informatico non esiste il linguaggio del momento, o preferito, o “più bello”.
      > Esiste un gruppo di lavoro con le sue competenze ed una problematica da risolvere.
      > Le considerazioni che seguono sono basate su dei test che non mirano ad essere esaustivi.
      > Lo scopo di quest’analisi è quello di porre domande e ottenere delle risposte.
      > Per cui chiunque non concordasse con i risultati e fosse in grado di aggiungere nuovi tasselli al mosaico che si sta andando a costruire è ben accetto.

      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.

      Non hai risposto alle mie domande però:

      > Mettiamo che io voglia fare un test di allocazione della memoria. Dovrei considerarlo valido oppure no.
      > I secondi spesi ad allocare 1.000.000 di oggetti list sarebbero velocità di python o del codice C che permette l’esecuzione del codice stesso?
      > Ma ancora se io facessi un algoritmo di ordinamento altamente inefficente il tempo di accesso agli elementi della lista (quella python) dovrebbe essere conteggiato come python o C.

      Purtroppo in queste settimane sono molto impegnato… ma appena possibile finirò la seconda parte dell’articolo facendo anche i test che suggerisci.

      A presto.

      • Ari  Il 25 novembre 2011 alle 12:46

        > Mettiamo che io voglia fare un test di allocazione della memoria. Dovrei considerarlo valido oppure no.
        > I secondi spesi ad allocare 1.000.000 di oggetti list sarebbero velocità di python o del codice C che permette l’esecuzione del codice stesso?

        Sarebbe un test valido. Python dovrebbe eseguire un ciclo su 1.000.000 di oggetti e scopriresti che sarebbe il ciclo la parte più onerosa. E il ciclo verrebbe eseguito direttamente da Python.

        > Quanti hanno la necessità di calcolare la media di un array di float o di eseguire il calcolo fattoriale?

        I linguaggi di scripting stanno andando per la maggiore proprio perché il grosso del collo di bottiglia è nella comunicazione con i database, mentre gli algoritmi puri sono diventati secondari. Leggi per esempio http://www.cringely.com/2011/10/the-second-coming-of-java/

        Né un sort né un calcolo di una media costituiscono un “caso comune”.
        Il calcolo della media, però, almeno utilizza il linguaggio. Il sort no.

        Un “caso comune” (molto più del sort) è, per esempio, l’utilizzo di Django, nel quale la maggior parte del tempo è speso nell’esecuzione di codice (Python!!) del framework.

Trackback

  • […] post Compilati VS interpretati passo 1.  di dikiyvolk ha sollevato un vespaio Anche perché ci sono tanti punti da esaminare. Mi propongo […]

  • […] Ma faccio finta di non accorgermi di niente e continuo con le mie robe Poi c’è un altro motivo per cui è stato difficile fare queste cose semplici-semplici: difficili da spiegare ai ggiovani –beati loro. Ma se leggete fino in fondo ci sarà la soluzione. OK, dopo queste doverose premesse, vado e continuo con le mie osservazioni al post di dikiyvolk Compilati VS interpretati passo 1. […]

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: