Possiamo formulare affermazioni generali sulle prestazioni del codice interpretato rispetto al codice compilato?

60

Sto confrontando due tecnologie al fine di raggiungere una raccomandazione per la quale una dovrebbe essere utilizzata da un'azienda. Il codice della tecnologia A viene interpretato mentre il codice della tecnologia B è compilato in codice macchina. Nel mio confronto dichiaro che la tecnologia B in generale avrebbe prestazioni migliori poiché non ha il sovraccarico aggiuntivo del processo di interpretazione. Dichiaro inoltre che, poiché un programma può essere scritto in molti modi, è ancora possibile che un programma scritto in tecnologia A possa superare quello scritto in tecnologia B.

Quando ho presentato questo rapporto per la revisione, il revisore ha affermato di non aver offerto una chiara motivazione per cui in generale il sovraccarico del processo di interpretazione sarebbe sufficientemente ampio da poter concludere che le prestazioni della tecnologia B sarebbero migliori.

Quindi la mia domanda è: possiamo mai dire qualcosa sulle prestazioni delle tecnologie compilate / interpretate? Se possiamo dire che la compilazione è generalmente più veloce e quindi interpretata, come potrei convincere il revisore del mio punto?

    
posta EpicSam 10.01.2017 - 13:34
fonte

14 risposte

111

No.

In generale, le prestazioni di un'implementazione linguistica dipendono principalmente dalla quantità di denaro, risorse, risorse umane, ricerca, ingegneria e sviluppo spesi su di essa.

In particolare, le prestazioni di un particolare programma dipendono principalmente dalla quantità di pensiero inserita nei suoi algoritmi.

Ci sono alcuni molto interpreti veloci là fuori, e alcuni compilatori che generano codice molto lento .

Per esempio, uno dei motivi per cui Forth è ancora popolare, è perché in molti casi, un programma Forth interpretato è più veloce del programma C compilato equivalente, mentre, allo stesso tempo, il programma utente scritto in Forth più l'interprete Forth scritto in C è più piccolo del programma utente scritto in C.

    
risposta data 10.01.2017 - 14:07
fonte
81

Le generalizzazioni e gli scenari specifici sono letteralmente opposti.

Sembra che tu sia in contraddizione con te stesso. Da un lato, vuoi fare una dichiarazione generale sui linguaggi interpretati e compilati. D'altro canto, si desidera applicare questa affermazione generale a uno scenario concreto che coinvolge la tecnologia A e la tecnologia B.

Una volta applicato qualcosa a uno scenario concreto, non è più generalizzato . Quindi, anche se puoi dimostrare che le lingue interpretate sono in generale più lente, non stai ancora esprimendo il tuo punto di vista. Il tuo revisore non si preoccupa delle generalizzazioni. Stai facendo un'analisi di due tecnologie molto specifiche. Questo è letteralmente il contrario della generalizzazione.

    
risposta data 10.01.2017 - 20:44
fonte
37

Come regola generale, un programma interpretato è circa 2x-10x più lento di quello che scrive il programma nella lingua ospite dell'interprete, con gli interpreti per i linguaggi più dinamici che sono più lenti. Questo perché il programma interpretato deve fare tutto il lavoro effettivo, ma ha anche l'overhead di interpretazione.

A seconda della struttura dell'interprete, possono esserci differenze molto significative. Esistono due scuole contraddittorie di progettazione dell'interprete: una dice che gli opcode devono essere il più piccoli possibile in modo che possano essere ottimizzati più facilmente, l'altro dice che gli opcode dovrebbero essere il più ampi possibile in modo da fare più lavoro all'interno dell'interprete. Quando la struttura del tuo programma corrisponde alla filosofia dell'interprete, l'overhead diventa trascurabile.

es. Perl è un linguaggio interpretato orientato alla manipolazione del testo. Un programma Perl idiomatico che esegue la manipolazione del testo non sarà molto più lento di un programma C, e potrebbe anche sovraperformare il programma C in alcuni casi (possibile perché Perl utilizza una rappresentazione di stringa diversa e include varie ottimizzazioni relative a testo e I / O). Tuttavia, fare il calcolo del numero in Perl sarà insopportabilmente lento. Un incremento ++x è una singola istruzione di assemblaggio, ma implica più traversamenti di puntatori e diramazioni per l'interprete Perl. Recentemente ho portato uno script Perl con collegamento CPU a C ++ e ottenuto un aumento di velocità 7x-20x, a seconda del livello di ottimizzazione del compilatore.

Parlare di ottimizzazioni è importante qui, dal momento che un interprete ottimizzato e ottimizzato può ragionevolmente sovraperformare un compilatore ingenuo non ottimizzante. Poiché creare un compilatore ottimizzante è difficile e richiede un grande sforzo, è improbabile che la tua "tecnologia B" abbia raggiunto questo livello di maturità.

(Nota: la lingua del computer Benchmarks Game sito ha una struttura confusa, ma una volta raggiunta la tabella dei tempi per un problema noterai che le prestazioni di vari linguaggi sono dappertutto - spesso, non c'è un chiaro limite di prestazioni tra compilato e soluzioni interpretate. La parte più importante del sito non sono i risultati del benchmark, ma le discussioni su quanto siano difficili i benchmark significativi.)

Quando si sceglie una tecnologia, le prestazioni di un runtime in linguaggio sono completamente irrilevanti. È più probabile che la tecnologia soddisfi alcuni vincoli di base (il nostro budget è $ x, dobbiamo essere in grado di consegnare prima di aaaa-mm-gg, dobbiamo soddisfare vari requisiti non funzionali) e che ha un valore inferiore costo totale di proprietà (factoring nella produttività degli sviluppatori, costi hardware, costi opportunità aziendali, rischio di bug e vincoli imprevisti nella tecnologia, costi di manutenzione, costi di formazione e di assunzione, ...). Per esempio. in un settore in cui il time-to-market è il fattore più importante, la tecnologia con la migliore produttività degli sviluppatori sarebbe la soluzione migliore. Per una grande organizzazione, la manutenzione e i costi a lungo termine potrebbero essere più interessanti.

    
risposta data 10.01.2017 - 14:52
fonte
18

Puoi assolutamente dire qualcosa sulle prestazioni delle tecnologie compilate / interpretate. Ma prima, devi definire "performance". Se stai costruendo un sistema embedded computazionalmente semplice, la "performance" probabilmente si sposterà verso il lato dell'uso della memoria delle cose. Mentre un sistema computazionalmente complesso che opera su grandi set di dati si troverebbe a definire "prestazioni" nel numero di calcoli per unità di tempo poiché l'overhead di memoria da JVM o .NET sarebbe trascurabile.

Una volta deciso quale "performance" è, allora si può dire qualcosa come "avremo 50 miliardi di oggetti in memoria in un dato momento e la techA interpretata aggiunge 8 byte aggiuntivi a ciascun oggetto per la gestione interna che equivale a un Memoria di memoria da 400 GB rispetto a TechB che non aggiunge questi dati "

    
risposta data 10.01.2017 - 14:02
fonte
12

Questa è una domanda tecnica e hai già molte buone risposte tecniche, ma vorrei sottolineare un aspetto leggermente diverso della tua situazione: il fatto che non puoi basare una decisione come "tecnologia A o tecnologia B "puramente per ragioni tecniche e / o prestazionali.

Gli aspetti tecnici di qualcosa di simile sono solo una piccola parte della decisione tra A e B. Ci sono dozzine di altri fattori da tenere a mente:

  • comporta costi di licenza? Ad esempio: devi pagare (una notevole quantità) per utilizzare un cluster di macchine SQL Server rispetto a un cluster di macchine PostgreSQL.
  • ho dipendenti che hanno familiarità con questa tecnologia (stack) e il suo ecosistema? Se sì, sono disponibili? Se no, posso assumerne qualcuno? Quanto mi costerà? O alleno quelli esistenti? Quanto mi costerà?
  • cosa vuole il cliente? Questo può essere un problema molto spesso.
  • la tecnologia che raccomando è pronta per l'uso di produzione? O è solo un hype attuale che forse si spegnerà? (ad esempio, pensa a Node.js quando è uscito)
  • la tecnologia che raccomando si adatta bene all'architettura esistente o all'architettura che avevo in mente? O devo spendere un sacco di soldi facendoli lavorare insieme senza problemi?
  • e molti altri aspetti che dipendono dalla tua situazione specifica.

Come puoi vedere, ci sono un sacco di cose da considerare quando prendi una decisione del genere.

So che questo non risponde in modo specifico alla tua domanda, ma penso che apporti una visione più generale della tua situazione e le specifiche di tale decisione.

    
risposta data 11.01.2017 - 13:16
fonte
10

La valutazione parziale è una struttura concettuale pertinente per mettere in relazione interpreti e compilatori.

Can we make general statements about the performance of interpreted code vs compiled code?

I linguaggi di programmazione sono specifiche (scritti in alcuni rapporti, come R5RS o n1570 ). Sono non software, quindi non ha nemmeno senso parlare di performance . Ma alcuni linguaggi di programmazione possono avere diverse implementazioni, tra cui interpreti e compilatori .

Anche nei linguaggi tradizionalmente compilati (cioè nelle lingue le cui implementazioni sono spesso compilatori) come C, alcune parti sono spesso interpretate. Ad esempio, la stringa di controllo del formato di printf (definita nello standard C) è spesso "interpretato" (dalla libreria standard C , che ha una funzione printf usando tecniche di argomenti variabili) ma alcuni compilatori (incluso GCC ) sono in grado -in limitato casi specifici - per ottimizzarlo e "compilarlo" in chiamate di livello inferiore.

E alcune implementazioni, anche all'interno di "interpreti", utilizzano tecniche di compilazione JIT (quindi generate la macchina codice su runtime ). Un buon esempio è luajit . Altre implementazioni (ad es. Python, Ocaml, Java, Parrot, Lua) stanno traducendo il codice sorgente in un bytecode che viene poi interpretato .

SBCL è un "compilatore" Common Lisp che traduce dinamicamente ogni REPL interazione (e chiama eval etc ...) nel codice macchina. Quindi ritieni che sia un interprete. La maggior parte delle implementazioni JavaScript nei browser (ad es. v8 ) utilizzano tecniche di compilazione JIT.

In altre parole, la differenza tra interpreti e compilatori è molto confusa (in realtà c'è un continuum tra entrambi) e, in pratica, la maggior parte delle implementazioni del linguaggio di programmazione ha spesso sia un interprete che un compilatore ( almeno al codice byte) facet.

Un'implementazione può essere veloce o lenta indipendentemente dall'utilizzo della maggior parte delle tecniche di "compilatore" o "interprete".

Alcuni tratti linguistici favoriscono un approccio interpretativo (e possono essere compilati in modo efficiente attraverso l'analisi dell'intero programma ).

Per alcuni tipi di problemi, progettare il software con alcuni approcci metaprogramming è utile e dà importanti accelerazioni. Potresti immaginare che, dato un input specifico, il tuo programma dinamicamente generi codice specializzato per elaborarlo. Questo è anche possibile con C o C ++ (usando una libreria JIT o generando un codice C, compilandolo come un plugin che viene caricato dinamicamente).

Vedi anche questa relativa domanda su Python e che

    
risposta data 11.01.2017 - 09:31
fonte
7

Per codice come A = A + B , che può compilare fino a una o due istruzioni macchina, ciascuna con un determinato numero di cicli. Nessun interprete può fare la stessa cosa in quel numero di cicli per una semplice ragione.

L'interprete esegue anche un proprio set di istruzioni (chiamali byte-codes, p-codes, intermediate language, qualunque cosa). Ogni volta che vede un codice byte come ADD, deve cercarlo in qualche modo e dirlo al codice che fa l'aggiunta.

La prossima volta che la vede, deve ripetere quella ricerca, a meno che non abbia un modo per ricordare la ricerca precedente. Se ha un modo per ricordare la ricerca precedente, non è più quello che chiamiamo un "interprete", ma piuttosto un compilatore just-in-time, o JITter.

On The Other Hand ...

Per codice come callSomeFunction( ... some args ...) , quanti cicli vengono spesi tra l'immissione di quel codice e l'uscita? Tutto dipende da cosa succede all'interno di callSomeFunction . Potrebbe essere un po ', e potrebbe essere trilioni, anche se callSomeFunction è compilato. Se è molto, non ha senso discutere i costi di interpretazione di quella linea di codice - il denaro è altrove.

Ricorda che le lingue interpretate hanno un valore proprio, ad esempio, non c'è bisogno di compilarle. (La "compilazione" della sintassi di superficie per i codici di byte richiede tempi trascurabili, ad esempio R o MATLAB.)

Inoltre, c'è flessibilità necessaria per livelli di programmazione intelligenti. In Minsky Society of Mind , capitolo 6.4 B -Brains, ci sono programmi A che si occupano del mondo, e ci sono programmi B che si occupano di programmi A, e ci possono essere ulteriori livelli. I programmi che scrivono e gestiscono altri programmi possono essere fatti più facilmente nei sistemi interpretativi.

In Lisp, puoi scrivere (+ A B) per aggiungere A e B, ma una volta scritto hai solo la possibilità di eseguirlo o meno. Puoi anche scrivere (eval (list '+ 'A 'B)) che costruisce il programma e poi lo esegue. Potrebbe costruire qualcosa di diverso.

L'argomento del programma è un altro programma . È più facile scrivere in un linguaggio interpretato (sebbene, come fa notare Jörg, le versioni più recenti di Lisp, mentre hanno eval , compile-on-the-fly, quindi non hanno la penalità di velocità dell'interpretazione).

    
risposta data 10.01.2017 - 14:38
fonte
5

In genere, dipende, ma come regola generale la compilazione - sia tramite JIT o compilata staticamente - l'ambiente sarà più veloce per molte attività di elaborazione intensiva - assumendo per semplicità lo stesso linguaggio.

Parte della ragione è che le lingue interpretate devono avere un loop di loop interprete che legge un'istruzione, seleziona l'azione appropriata da intraprendere e la esegue. Nel migliore dei casi, come interpretare il bytecode Python o Java (come ha fatto la vecchia JVM) ha un sovraccarico di poche istruzioni e ha devastato il predittore del ramo - senza l'ultimo si possono aspettare enormi penalità a causa di previsioni errate. Anche un JIT molto stupido dovrebbe accelerare significativamente.

Detto questo la lingua interpretata può imbrogliare. Ad esempio Matlab ha routine ottimizzate per la moltiplicazione delle matrici e con poche modifiche è possibile ottenere codice in esecuzione su GPU (dichiarazione di non responsabilità: lavoro per nVidia - qualsiasi opinione espressa qui è mia e non rappresenta la vista del mio datore di lavoro). In questo modo puoi scrivere codice di livello superiore breve e potente senza preoccuparti dei dettagli: qualcuno si è preso cura di esso e ha investito tempo e risorse per ottimizzarlo in un linguaggio di basso livello. Non c'è nulla di ereditato al riguardo e non impedisce, ad esempio, a Matlab di JIT il codice, ma spesso non vi è alcun motivo in quanto il sovraccarico nel chiamare la routine di alto livello è minimo rispetto al tempo trascorso in quelli di basso livello.

TL; DR - i programmi compilati hanno enormi vantaggi in termini di prestazioni rispetto a quelli interpretati (per il confronto tra mele e mele vedi Velocità PyPy ). Tuttavia, la velocità dell'eseguibile è solo una parte del problema e potrebbe non contribuire molto alla velocità generale (se il tempo è per lo più speso nelle librerie). Anche l'implementazione è importante.

    
risposta data 11.01.2017 - 09:09
fonte
5

La tua ipotesi è fondata, sebbene sia una supposizione.

Non ho intenzione di esaminare le ragioni per cui il codice compilato dovrebbe essere più veloce del codice interpretato: se sai come funzionano i computer, sarà ovvio. La differenza può essere di ordine di grandezza per alcuni tipi di problemi. Se il tuo revisore contesta seriamente questo caso generale, non sanno di cosa stanno parlando.

Dove possono avere un punto è se la differenza è significativa nel tipo di applicazione che stai sviluppando. Se è principalmente I / O o principalmente chiama librerie compilate e non ha molti calcoli, il sovraccarico del processo di interpretazione potrebbe effettivamente essere insignificante.

Ma il punto del mio post è questo: come un I.T. esperto sarete spesso chiamati a prendere decisioni improvvise sulla base di una conoscenza generale di come le cose dovrebbero funzionare. Fare un test specifico potrebbe fornirti una risposta più precisa, ma costerà molto di più e non ti porterà prima lì.

Ma di tanto in tanto ti fai prendere alla sprovvista. È successo a me. Fai una buona ipotesi e poi scopri di non aver tenuto conto della stupidità del mondo.

Ma non posso spiegare oltre al mio cartone animato preferito di Dilbert di tutti i tempi. Niente mostra meglio di questo i pericoli di essere un furbo.

TL; DR: dovresti avere ragione, ma controlla il mondo reale per ogni evenienza.

    
risposta data 13.01.2017 - 09:53
fonte
3

Se non usi qualcosa di un po 'esotico, il tuo problema non riguarderà le prestazioni di un linguaggio interpretato A e del linguaggio compilato B.

Perché se tu / la tua squadra conoscete A e non B e quindi scrivete un codice migliore in A che in B, potete avere prestazioni molto migliori in A che in B. Se avete persone esperte in una lingua e nella lingua / nelle librerie può fare il lavoro che ti serve, attenerci ad esso.

Ecco un link su regex in varie lingue; vedrai che le regex sono implementate meglio in alcune lingue, anche se compilate o meno: link

    
risposta data 10.01.2017 - 14:04
fonte
1

Penso che non sia una buona idea parlare di prestazioni di due tecnologie basandosi semplicemente sul fatto che uno è compilato e l'altro è interpretato. Come affermato in altre risposte, può dipendere dall'area di applicazione (alcune lingue possono essere ottimizzate per eseguire alcune operazioni molto rapidamente e fare altre cose più lentamente) e dall'esperienza delle persone che stanno per usare quella tecnologia.

Non penso che sia ragionevole aspettarsi un miglioramento delle prestazioni se si prendono alcuni eccellenti codificatori linguistici interpretati e si dà loro una tecnologia che non hanno familiarità con loro - forse in teoria il secondo MAGGIO può portare a prestazioni migliori, ma in realtà, senza le competenze e l'esperienza necessarie, non utilizzerai tutte le opportunità di ottimizzazione.

Da uno dei ben noti impiegati della Silicon Valley ho anche sentito che preferiscono il linguaggio che è più semplice da usare in quanto è più costoso e difficile pagare alcuni sviluppatori esperti per mantenere un codice complicato, ma altamente ottimizzato oltre a comprare più rig per affrontare l'implementazione meno efficiente, quindi è necessario prendere in considerazione anche la scelta della tecnologia.

    
risposta data 11.01.2017 - 11:11
fonte
0

Una volta ho dovuto fare una dichiarazione simile per giustificare una grande decisione.

In primo luogo, potrebbero non voler credere a un umile ingegnere, quindi ho trovato alcuni test comparativi comparabili e li ho citati. Ce ne sono molti, da persone come Microsoft o rinomate università. E diranno cose come: il metodo A è tra 3 e 10 volte più veloce del metodo B, a seconda delle variabili X e Y.

In secondo luogo, potresti voler eseguire un benchmark personalizzato, magari utilizzando una porzione rappresentativa del codice in questione o qualcosa di simile che hai già. Eseguilo 1000 volte durante la notte, quindi c'è davvero una differenza misurabile.

A questo punto la differenza (o la mancanza di essa) tra A e B dovrebbe essere così chiara che devi solo presentarla. Quindi, formattate i risultati in modo chiaro, con i diagrammi se possibile, indicando tutte le ipotesi e definendo tutti i dati utilizzati.

    
risposta data 12.01.2017 - 15:01
fonte
0

Direi che qualsiasi linguaggio dinamico ha un vantaggio rispetto a quelli compilati staticamente: "Ottimizzazioni del runtime"

Questo è uno dei motivi per cui Java può essere più veloce di C ++

Sì, caricamento un linguaggio digitato in modo dinamico avrà sempre il costo della traduzione e sarà svantaggiato. Ma una volta eseguito, l'interprete può tracciare e migliorare percorsi di codice frequenti con informazioni di runtime che i linguaggi statici non avranno mai

NOTA: Bene, Java è un linguaggio interpretato, non dinamico. Ma è un ottimo esempio di ciò che puoi accelerare con le informazioni di runtime

    
risposta data 14.01.2017 - 09:26
fonte
-3

... I also state that since a program could be written in many ways it is still possible a program written in tech A could outperform one written in tech B.

When I submitted this report for review, the reviewer stated that I offered no clear reason why in general the overhead of the interpretation process would be large enough that we could conclude that tech B's performance would be better. ...

Questo sarebbe il mio approccio:

In generale, gli interpreti sono compilati, quindi ogni tecnologia interpretata non è altro che una tecnologia compilata se guardata a un livello basso. Pertanto, le tecnologie compilate sono solo di più e con più possibilità non puoi mai peggiorare se sei intelligente (che in generale sei). Dipende da quante informazioni sono disponibili al momento della compilazione e quante informazioni sono disponibili solo al runtime e quanto sono validi i compilatori e gli interpreti, ma dovrebbe teoricamente essere sempre possibile almeno pari alla prestazione di qualsiasi interprete con un compilatore adatto, solo perché gli interpreti sono fabbricati da compilatori. Che sia possibile, non significa che sia il caso dei tuoi tecnici A e B però.

In pratica, basta dire al revisore su tutti i benchmark disponibili dove vengono confrontati i sistemi compilati e interpretati. Poi chiedigli di suggerire un interprete che batte il tuo algoritmo specifico codificato Assembly ottimizzato.

Si dovrebbe forse aggiungere che nessuna di queste affermazioni generali non aiuta affatto nel confrontare due specifici tech A e B. Qui la scelta di A e B conta molto, molto di più, che se fossero interpretati o compilati.

    
risposta data 12.01.2017 - 12:03
fonte