2012-12-11 19 views
16

Se dovessi indovinare, sono abbastanza sicuro che la risposta sia Clojure, ma non sono sicuro del perché. Logicamente (per me) sembra ClojureScript dovrebbe essere più veloce:Quale è più veloce, Clojure o ClojureScript (e perché)?

Entrambi sono "dinamica", ma ClojureScript

  • compila in JavaScript, in esecuzione su V8 ​​
  • motore V8 è senza dubbio il motore di lingua veloce dinamico c'è
  • V8 è scritto in C

mentre Clojure:

  • È anche dinamico
  • Viene eseguito in JVM, che non ha alcun supporto dinamico integrato, così sto pensando in tal modo JVM ha a che fare tutto ciò V8 sta facendo troppo, per abilitare il supporto dinamico
  • e Java è più lento C

Quindi, come potrebbe Clojure essere più veloce di ClojureScript? "Dinamico" significa qualcosa di diverso quando si dice che JavaScript è dinamico e Clojure è dinamico? Cosa non vedo?

(Naturalmente, se ClojureScript è effettivamente più veloce, quindi è il ragionamento di cui sopra è corretto?)

immagino, cosa Clojure compilare a .... è almeno una parte della questione. So che la parte JVM non può essere solo un semplice interprete (altrimenti ClojureScript sarebbe più veloce), ma Clojure non può essere compilato con il normale codice byte, in quanto non esiste una "dinamica" nella JVM. Quindi, qual è la differenza tra come ClojureScript viene compilato/eseguito e come Clojure viene compilato/excecuted e come Java viene compilato/eseguito e le differenze di prestazioni implicite in ciascuna di esse?

+5

"Java è più lento di C" può essere vero per molti domini problematici, ma è irrilevante. La domanda appropriata è "Java è più lento di V8". V8 non esegue il tuo codice come codice C compilato, è un interprete JavaScript che sembra scritto in C. –

+0

@EricJ. Immagino che questa sia la mia domanda allora, sto vedendo V8 interpretare JavaScript generato da Clojure rispetto a una JVM che interpreta Clojure. V8 compila il JS fino al codice macchina e lo esegue. Che cosa fa la JVM più veloce? – lobsterism

+1

Clojure è compilato in byte code, proprio come Java. Cosa ti ha fatto pensare che non fosse? –

risposta

24

Questa domanda è difficile da rispondere con precisione, senza riferimento a un'attività di benchmark specifico (o anche a versioni specifiche di Clojure o ClojureScript).

Detto questo, nella maggior parte dei casi mi aspetto che Clojure sia un po 'più veloce. Motivi:

  • Clojure solito compila verso il basso per codice statico, quindi in realtà non fa alcun lookup dinamico in fase di esecuzione. Questo è abbastanza importante: il codice ad alte prestazioni spesso produce bytecode che è molto simile a Java tipizzato staticamente. Sembra che la domanda faccia il falso presupposto che un linguaggio dinamico debba fare ricerche di metodo dinamiche in runtime: questo non è sempre il caso (e di solito non è in Clojure)
  • JIT JVM è molto ben progettato, e io credo che al momento sia ancora un po 'meglio delle JIT JavaScript, nonostante il buon V8.
  • Se hai bisogno di concorrenza o hai bisogno di sfruttare più core allora chiaramente non c'è contest poiché JavaScript è single-threaded .....
  • Il compilatore Clojure è più maturo di ClojureScript, e ha avuto parecchio del lavoro di ottimizzazione delle prestazioni negli ultimi anni (inclusi cose come supporto primitivo, protocolli ecc.)

Naturalmente, è possibile scrivere codice veloce o lento in qualsiasi lingua. Questo farà più differenza rispetto alla differenza fondamentale tra le implementazioni linguistiche.

E in sostanza, la scelta tra Clojure e ClojureScript non deve riguardare in alcun caso le prestazioni. Entrambi offrono vantaggi di produttività convincenti.Il fattore decisivo principale dovrebbe essere:

  • Se si desidera eseguire sul web, utilizzare ClojureScript
  • Se si desidera eseguire sul server in un Environnment JVM, utilizzare Clojure
+0

Ok, penso che il tuo primo punto fosse la mia fonte di confusione. Quindi stai dicendo che se qualcuno stava "abusando" delle cose dinamiche e il runtime stava facendo continuamente ricerche dinamiche, allora chissà quale sarebbe stato più veloce, ma non è il caso del 99% delle volte e il codice bytecode batte il codice interpretato lì, destra? Hai idea di quale sarebbe la differenza di prestazioni%? Suppongo che se l'esecuzione normale è il collo di bottiglia, allora è la stessa differenza in termini di% rispetto a JS vs Java? – lobsterism

+2

Sì, Java e JavaScript probabilmente daranno all'incirca la differenza% tra Clojure ottimamente ottimizzato e ClojureScript ottimamente ottimizzato. Le rispettive piattaforme sono il fattore limitante, dopotutto ..... a lungo termine ci si può aspettare che Clojure tenga conto delle prestazioni Java e ClojureScript tendere verso le prestazioni di JavaScript man mano che i compilatori migliorano sempre di più. – mikera

28

In realtà, V8 è scritto in C++. Tuttavia, fa fondamentalmente la stessa cosa della JVM, e JVM è scritto nel codice Javascript JITs di C. V8 ed esegue il codice JIT. Allo stesso modo JIT JIT compila (o compila hotspot) bytecode (NON Java) ed esegue quel codice generato.

Bytecode non è statico, come Java. In effetti può essere abbastanza dinamico. Java, d'altra parte, è per lo più statico e non è corretto confondere Java con il bytecode. Il compilatore java trasforma il codice sorgente Java in bytecode e JVM esegue il bytecode. Per ulteriori informazioni, ti consiglio di guardare il blog di John Rose (example). Ci sono molte buone informazioni lì. Inoltre, prova a cercare i discorsi di Cliff Click (come).

Allo stesso modo, il codice Clojure viene compilato direttamente in bytecode e la JVM esegue quindi lo stesso processo con quel bytecode. Compilare Clojure viene solitamente eseguito in fase di runtime, che non è il processo più veloce. Allo stesso modo, anche la traduzione di Clojurescript in Javascript non è veloce. La traduzione di V8 di Javascript in forma eseguibile è ovviamente abbastanza veloce. Clojure può essere in anticipo compilato in bytecode e ciò può eliminare un sacco di sovraccarico di avvio.

Come hai detto, non è proprio corretto dire che JVM interpreta bytecode. La versione 1.0 lo ha fatto più di 17 anni fa!

Tradizionalmente, c'erano due modalità di compilazione. La prima modalità è un compilatore JIT (Just in Time). Dove bytecode è tradotto direttamente nel codice macchina.La compilazione JIT di Java viene eseguita rapidamente e non genera codice altamente ottimizzato. Funziona OK.

La seconda modalità è denominata il compilatore di hotspot. Il compilatore di hotspot è molto sofisticato. Avvia il programma molto rapidamente in modalità interpretata e lo analizza mentre il programma viene eseguito. Come rileva gli hotspot (punti nel codice che vengono eseguiti frequentemente), li compilerà. Mentre il compilatore JIT deve essere veloce perché nulla viene eseguito a meno che non sia JIT, il compilatore di hotspot può permettersi di dedicare ulteriore tempo per ottimizzare il moccio dal codice che sta compilando.

Inoltre, può tornare indietro e rivisitare quel codice in seguito e applicare ulteriori ottimizzazioni su di esso se necessario e possibile. Questo è il punto in cui il compilatore hotspot può iniziare a battere C/C++ compilato. Poiché ha una conoscenza runtime del codice, può permettersi di applicare le ottimizzazioni che un compilatore C/C++ statico non può fare. Ad esempio, può integrare funzioni virtuali.

Hotspot ha un'altra caratteristica, che in base alle mie conoscenze nessun altro ambiente ha, può anche deoptimizzare il codice se necessario. Ad esempio, se il codice prendesse continuamente un singolo ramo, e ciò fosse ottimizzato e le condizioni di runtime cambiassero forzando il codice verso il basso, l'altro ramo (non ottimizzato) e le prestazioni diventerebbero improvvisamente terribili. L'hotspot può deoptimizzare tale funzione e ricominciare l'analisi per capire come farlo funzionare meglio.

Uno svantaggio di hotspot è che inizia un po 'lento. Una modifica della JVM di Java 7 è stata la combinazione del compilatore JIT e del compilatore di hotspot. Questa modalità è nuova, tuttavia, e non è l'impostazione predefinita, ma una volta avviata l'avvio dovrebbe essere buona e quindi è possibile iniziare la advanced optimizations che la JVM è così buona.

Cheers!

+0

Grazie, in realtà non avevo idea che la JVM supportasse le dinamiche. Googling però mi sono imbattuto in http://blog.fogus.me/2011/10/14/why-clojure-doesnt-need-invokedynamic-but-it-might-be-nice, il che dimostra che Clojure in realtà non è nemmeno approfittare di questa funzionalità, ma mi aiuta anche a capire perché può essere ancora veloce. – lobsterism

+0

Se guardi la nota chiave di Rich Hickey Clojure Conj dello scorso anno, parla del supporto per quella funzione. Sarebbe bello, ma ci sarebbero problemi con le JVM più vecchie. – Bill

+1

Inoltre, ho dimenticato di aggiungere la risposta effettiva alla tua domanda. Dipende. ;-) – Bill

1

Questo è non tanto una risposta quanto un commento storico: sia la HotSpot VM che il motore V8 js possono avere le loro origini tracciate nel progetto Self di Sun Microsystems, che ritengo abbia prototipato molta della tecnologia che consente loro di funzionare alla stessa velocità fare. Qualcosa da considerare quando si confrontano entrambi. Avrei postato questo come commento ma il sistema di reputazione mi ha impedito.

Problemi correlati