Cosa fa rallentare Ruby?



performance garbage-collection (6)

Il rubino è lento. Ma quali sono le parti più problematiche?

Fa "late lookup" per i metodi, per consentire flessibilità. Questo rallenta un po '. Inoltre, deve ricordare i nomi delle variabili per ogni contesto per consentire l'eval, quindi i suoi frame e le sue chiamate di metodo sono più lenti. Inoltre attualmente manca un buon compilatore JIT, sebbene MRI 1.9 abbia un compilatore bytecode (che è meglio), e jruby lo compila in java bytecode, che poi (può) compilare tramite il compilatore JIT di JSM di HotSpot, ma finisce per essere circa la stessa velocità di 1.9.

Quanto influisce il garbage collector sulle prestazioni? So che ho avuto momenti in cui eseguire il garbage collector da solo ha richiesto diversi secondi, soprattutto quando si lavora con le librerie OpenGL.

da alcuni dei grafici di http://www.igvita.com/2009/06/13/profiling-ruby-with-googles-perftools/ direi che ci vuole circa il 10% che è un po '- puoi diminuisci quello colpito aumentando malloc_limit in gc.c e ricompilando.

Ho usato le librerie matematiche Matrix con Ruby che sono state particolarmente lente. C'è un problema con il modo in cui il rubino implementa la matematica di base?

Ruby 1.8 "non ha" implementato la matematica di base ha implementato classi numeriche e tu chiameresti cose come Fixnum # + Fixnum # / una volta per chiamata - che era lento. Ruby 1.9 trucchi un po 'inserendo alcune delle operazioni matematiche di base.

Ci sono caratteristiche dinamiche in Ruby che semplicemente non possono essere implementate in modo efficiente? Se sì, in che modo altri linguaggi come Lua e Python risolvono questi problemi?

Cose come Eval sono difficili da implementare in modo efficiente, anche se molto lavoro può essere fatto, ne sono sicuro. Il kicker per Ruby è che deve adattarsi a qualcuno in un altro thread che modifica la definizione di una classe spontaneamente, quindi deve essere molto prudente.

C'è stato un lavoro recente che ha migliorato significativamente le prestazioni?

1.9 è come un 2x speedup. È anche più efficiente nello spazio. JRuby cerca costantemente di migliorare la velocità [e probabilmente dedica meno tempo al GC rispetto al KRI]. Oltre a questo non sono a conoscenza di molto, tranne piccole cose per hobby su cui ho lavorato. Si noti inoltre che le stringhe 1.9 sono a volte più lente a causa della codifica della cordialità.

Ruby è lento a certe cose. Ma quali sono le parti più problematiche?

Quanto il garbage collector influisce sulle prestazioni? So che ho avuto momenti in cui eseguire il garbage collector da solo ha richiesto diversi secondi, soprattutto quando si lavora con le librerie OpenGL.

Ho usato le librerie matematiche Matrix con Ruby che sono state particolarmente lente. C'è un problema con il modo in cui il rubino implementa la matematica di base?

Ci sono caratteristiche dinamiche in Ruby che semplicemente non possono essere implementate in modo efficiente? Se sì, in che modo altri linguaggi come Lua e Python risolvono questi problemi?

C'è stato un lavoro recente che ha migliorato significativamente le prestazioni?


Answer #1

Hmm - Ho lavorato a un progetto alcuni anni fa, dove ho raschiato la canna con le prestazioni di Ruby, e non sono sicuro che sia cambiato molto da allora. In questo momento è il caveat emptor - devi sapere di non fare certe cose, e francamente i giochi / le applicazioni in tempo reale sarebbero uno di questi (dato che hai menzionato OpenGL).

Il colpevole dell'uccisione delle prestazioni interattive è il garbage collector - altri qui menzionano che anche Java e altri ambienti hanno la garbage collection, ma Ruby's deve fermare il mondo . Vale a dire, deve smettere di eseguire il programma, scansionare da zero ogni registro e il puntatore della memoria, segnare la memoria che è ancora in uso e liberare il resto. Il processo non può essere interrotto mentre questo accade e, come potresti aver notato, può richiedere centinaia di millisecondi.

La sua frequenza e durata di esecuzione è proporzionale al numero di oggetti creati e distrutti, ma a meno che non lo disabiliti del tutto, non hai alcun controllo. La mia esperienza è stata che c'erano diverse strategie insoddisfacenti per appianare il mio loop di animazione Ruby:

  • GC.disable / GC.enable attorno a loop di animazione critici e forse a un GC.start opportunistico per forzarlo ad andare quando non può fare alcun danno. (Poiché la mia piattaforma di destinazione all'epoca era una macchina Windows NT da 64 MB, questo a volte causava l'esaurimento della memoria del sistema, ma fondamentalmente è una cattiva idea - a meno che non si possa calcolare la quantità di memoria necessaria prima di fare ciò, stai rischiando esaurimento della memoria)
  • Riduci il numero di oggetti che crei in modo che il GC abbia meno lavoro da fare (riduce la frequenza / lunghezza della sua esecuzione)
  • Riscrivi il tuo loop dell'animazione in C (un cop-out, ma quello con cui sono andato!)

In questi giorni probabilmente vedrei anche se JRuby potrebbe funzionare come un runtime alternativo, poiché credo che si basi sul più sofisticato garbage collector di Java.

L'altro grosso problema di prestazioni che ho riscontrato è l'I / O di base quando provo a scrivere un server TFTP in Ruby qualche tempo fa (sì, ho scelto tutte le lingue migliori per i miei progetti critici per le prestazioni, questo era solo un esperimento). Il ciclo più stretto assoluto più semplice per rispondere semplicemente a un pacchetto UDP con un altro, contando il prossimo pezzo di un file, deve essere stato circa 20 volte più lento della versione C standard. Sospetto che potrebbero esserci stati dei miglioramenti da fare in base all'utilizzo di IO di basso livello (sysread ecc.) Ma la lentezza potrebbe essere semplicemente nel fatto che non esiste un tipo di dati di byte di basso livello - ogni piccola lettura è copiata in un Stringa. Questa è solo una congettura, però, non ho seguito molto questo progetto ma mi ha avvisato di non fare affidamento su I / O scattanti.

L'aumento recente della velocità principale che è andato avanti, sebbene non sia completamente aggiornato qui, è che l'implementazione della macchina virtuale è stata rifatta per 1.9, con conseguente esecuzione del codice più veloce. Comunque non penso che il GC sia cambiato , e sono abbastanza sicuro che non ci sia nulla di nuovo sul fronte I / O. Ma non sono completamente aggiornato su Ruby che non ha problemi, quindi qualcun altro potrebbe voler fare il chip qui.


Answer #2

La parte più problematica è "tutti".

Punti bonus se quel "tutti" non ha mai usato la lingua, mai.

Seriamente, 1.9 è molto più veloce e ora è alla pari con python, e jruby è più veloce di jython.

I netturbini sono ovunque; ad esempio, Java ne ha uno ed è più veloce di C ++ sulla gestione dinamica della memoria. Il rubino non è adatto per il numero di crunch; ma sono poche le lingue, quindi se hai parti di calcolo intensivo nel tuo programma in qualsiasi lingua, è meglio riscriverle in C (Java è veloce con la matematica a causa dei suoi tipi primitivi, ma ha pagato a caro prezzo per loro, sono chiaramente # 1 nelle parti più brutte della lingua).

Per quanto riguarda le caratteristiche dinamiche: non sono veloci, ma il codice senza di esse in lingue statiche può essere anche più lento; per esempio, java usa una configurazione XML invece di Ruby usando una DSL; e probabilmente sarebbe SLOWER poiché l'analisi XML è costosa.


Answer #3

Presumo che tu stia chiedendo "quali tecniche particolari in Ruby tendono ad essere lente".

Uno è l'istanziazione di oggetti. Se ne stai facendo grandi quantità, vuoi vedere (ragionevoli) modi per ridurlo, come usare il modello del peso mosca , anche se l'utilizzo della memoria non è un problema. In una libreria in cui l'ho rielaborato per non creare molti oggetti molto simili più e più volte, ho raddoppiato la velocità complessiva della libreria.


Answer #4

Ruby è molto buono per fornire soluzioni rapidamente. Meno per la consegna di soluzioni rapide. Dipende dal tipo di problema che stai cercando di risolvere. Mi vengono in mente le discussioni sul vecchio forum CompuServe MSBASIC nei primi anni '90: quando è stato chiesto quale fosse più veloce per lo sviluppo di Windows, VB o C, la risposta abituale era "VB, di circa 6 mesi".

Nella sua forma MRI 1.8, Ruby è relativamente lento a eseguire alcuni tipi di attività ad alta intensità di calcolo. Praticamente qualsiasi linguaggio interpretato soffre in questo modo rispetto alla maggior parte dei linguaggi compilati mainstream.

Le ragioni sono diverse: alcune facilmente indirizzabili (la primitiva raccolta dei rifiuti in 1.8, ad esempio), altre meno.

1.9 affronta alcuni dei problemi, anche se probabilmente ci vorrà del tempo prima che diventi generalmente disponibile. Alcune delle altre implementazioni che hanno come obiettivo i runtime pre-esistenti, JRuby, IronRuby, MagLev per esempio, hanno il potenziale per essere significativamente più veloci.

Per quanto riguarda le prestazioni matematiche, non sarei sorpreso di vedere un throughput piuttosto lento: è parte del prezzo che si paga per precisione arbitraria. Ancora una volta, scegli il tuo problema. Ho risolto oltre 70 problemi di Project Euler in Ruby con quasi nessuna soluzione che richiede più di un mintue da eseguire. Quanto velocemente ne hai bisogno per correre e quanto ne hai bisogno?


Answer #5

Ruby 1.9.1 è circa il doppio della velocità di PHP e un po 'più veloce di Perl, secondo alcuni benchmark.

(Aggiornamento: La mia fonte è this ( screenshot ). Non so quale sia la sua fonte, però.)

Ruby non è lento. Il vecchio 1.8 è, ma l'attuale Ruby non lo è.





dynamic-languages