Perché Go è così lento (rispetto a Java)?


109

Come abbiamo potuto vedere da The Computer Language Benchmarks Game nel 2010:

  • Go è in media 10 volte più lento di C
  • Go è 3 volte più lento di Java !?

Come può essere, tenendo presente che il compilatore Go produce codice nativo per l'esecuzione?
Compilatori immaturi per Go? O c'è qualche problema intrinseco con la lingua Go?

EDIT: la
maggior parte delle risposte nega l'intrinseca lentezza di Go languge, sostenendo che il problema risiede in compilatori immaturi.
Pertanto ho fatto dei test per calcolare i numeri di Fibonacci : l'algoritmo iterativo viene eseguito in Go (freebsd, 6g) con la samevelocità come in C (con l'opzione O3). Quello ricorsivo opaco viene eseguito in Go 2 timespiù lentamente che in C (con l'opzione -O3; con -O0 - lo stesso). Ma non ho visto 10 volte cadere come nel gioco dei benchmark.


36
Per essere onesti, C è ASM sotto mentite spoglie e Java ha alcune serie ottimizzazioni sotto il cofano in questi giorni.
Matthew Scharley

16
Forse anche il benchmark non riflette i punti di forza di Go. È possibile che altri benchmark siano effettivamente più veloci di questo. Inoltre, spesso non sono le prestazioni ma la leggibilità del codice che conta di più.
extraneon

7
@extraneon: sono d'accordo. Ricorda, Go è progettato per Google e Google esegue regolarmente codice su 2 milioni di core. Il gioco Benchmarks utilizza solo 4 core, credo.
Jörg W Mittag

4
@extraneon: Sono d'accordo in generale, ma Go è stato specificamente progettato pensando alla velocità, come in "i programmi risultanti vengono eseguiti quasi velocemente quanto il codice C o C ++ comparabile."
shosti

4
La tua domanda presume troppo: "La maggior parte delle risposte nega la lentezza intrinseca di Go languge" è una frase errata per l'uso in una domanda. Hai una domanda da porre o una dichiarazione da fare? Consulta c2.com/cgi/wiki?HostileStudent per comprendere il tuo errore.
Chris

Risposte:


102

I compilatori 6g e 8g non sono particolarmente ottimizzati, quindi il codice che producono non è particolarmente veloce.

Sono progettati per funzionare velocemente e produrre codice che va bene (c'è un po 'di ottimizzazione). gccgoutilizza i passaggi di ottimizzazione esistenti di GCC e potrebbe fornire un confronto più mirato con C, ma gccgo non è ancora completo di funzionalità.

I dati di riferimento riguardano quasi esclusivamente la qualità dell'attuazione. Non hanno molto a che fare con il linguaggio in quanto tale, tranne nella misura in cui l'implementazione impiega il runtime a supportare le funzionalità del linguaggio di cui il benchmark non ha realmente bisogno. Nella maggior parte dei linguaggi compilati un compilatore sufficientemente intelligente potrebbe in teoria eliminare ciò che non è necessario, ma arriva un punto in cui stai truccando la demo, poiché pochissimi utenti reali del linguaggio scriverebbero programmi che non usano quella caratteristica . Spostare le cose senza rimuoverle completamente (ad esempio, prevedere le destinazioni delle chiamate virtuali in Java compilato con JIT) inizia a diventare complicato.

FWIW, il mio test molto banale con Go quando lo stavo esaminando (un ciclo di addizione di interi, fondamentalmente), gccgo ha prodotto codice verso l'estremità veloce dell'intervallo tra gcc -O0e gcc -O2per l'equivalente C. Go non è intrinsecamente lento, ma i compilatori non fanno ancora tutto. Non sorprende per una lingua vecchia di 10 minuti.


7
Inoltre, è possibile che i programmi Go in The Computer Language Benchmarks Game non siano ottimizzati come lo sono C e Java.
el.pescado

E tra gcc -O0 e gcc -O3? C'è anche l'intenzione che i compilatori "facciano tutto"?
igouy

@igouy: beh, sono abbastanza sicuro che ci sia un'intenzione che gccgo farà la garbage collection, cosa che attualmente non fa. Ci sono ancora alcune funzionalità da inserire anche nei compilatori g, ad esempio attualmente non utilizzano i thread host particolarmente bene (in particolare, lo scheduler goroutine non è preventivo). Oltre a ciò, non conosco i piani di Google, se i compilatori g saranno mai ferocemente ottimizzati o se solo gccgo lo farà.
Steve Jessop

1
@xitrium: Penso che l'intenzione di Go sia che le implementazioni non dovrebbero essere richieste per pianificare in modo cooperativo, possono anticipare se lo desiderano. Vedi ad esempio code.google.com/p/go/issues/detail?id=543 , che non è stato chiuso come "senza senso, correggere questo cosiddetto bug sarebbe in contraddizione con la definizione della lingua Go", che dovrebbe essere se È vietato anticipare le implementazioni di Go :-) Il problema era aggravato dal fatto che per impostazione predefinita Go utilizzava solo un singolo thread host, indipendentemente dal numero di goroutine eseguibili.
Steve Jessop

6
La risposta potrebbe essere un po 'obsoleta a partire da ora. Recentemente è stata rilasciata la prima beta di Go 1.1 , affermano che le prestazioni dei programmi compilati aumentano di circa il 30% al 40%. Qualcuno, per favore, faccia di nuovo questi test.
fuz

51

Nella prossima versione delle domande frequenti su Go , dovrebbe apparire qualcosa di simile al seguente.

Prestazione

Perché Go si comporta male nel benchmark X?

Uno degli obiettivi di progettazione di Go è avvicinarsi alle prestazioni di C per programmi comparabili, ma su alcuni benchmark funziona piuttosto male, inclusi diversi in test / banco. I più lenti dipendono dalle librerie per le quali versioni con prestazioni comparabili non sono disponibili in Go. Ad esempio, pidigits dipende da un pacchetto matematico multi-precisione e le versioni C, a differenza di Go, usano GMP (che è scritto in assemblatore ottimizzato). I benchmark che dipendono dalle espressioni regolari (regex-dna, ad esempio) stanno essenzialmente confrontando il pacchetto regexp stopgap di Go con librerie di espressioni regolari mature e altamente ottimizzate come PCRE.

I giochi benchmark si ottengono con una messa a punto approfondita e le versioni Go della maggior parte dei benchmark richiedono attenzione. Se misuri programmi C e Go comparabili (il complemento inverso è un esempio), vedrai che i due linguaggi sono molto più vicini nelle prestazioni grezze di quanto indicherebbe questa suite.

Tuttavia, c'è spazio per miglioramenti. I compilatori sono buoni ma potrebbero essere migliori, molte librerie necessitano di grandi prestazioni e il garbage collector non è ancora abbastanza veloce (anche se lo fosse, fare attenzione a non generare inutili spazzatura può avere un effetto enorme).

Ed ecco alcuni dettagli in più su The Computer Benchmarks Game da un recente thread della mailing list.

Garbage collection e prestazioni in gccgo (1)

Garbage collection e prestazioni in gccgo (2)

È importante notare che il Computer Benchmarks Game è solo un gioco. Le persone con esperienza nella misurazione delle prestazioni e nella pianificazione delle capacità corrispondono con attenzione come con carichi di lavoro reali ed effettivi; non giocano.


1
E qui alcuni dettagli dallo stesso thread che hai escluso: groups.google.com/group/golang-nuts/msg/2e568d2888970308
igouy

3
È importante notare che "i benchmark sono un pasticcio" - non solo i benchmark pubblicati come gioco di benchmark - shootout.alioth.debian.org/flawed-benchmarks.php
igouy

18
(e tutti ...) Certo è un "gioco" , ma quando vedo che Go è solo due volte più lento del più veloce su questi benchmark, la mia prima impressione è "wow, Go sembra veloce" , perché so che questi benchmark sono imperfetto. Al contrario, quando vedo Ruby essere 65 volte più lento del più veloce, penso a me stesso "non userò Ruby per il mio prossimo sforzo simultaneo ad alta intensità numerica" . Quindi può essere un "gioco", ma c'è del vero se lo prendi con le pinze.
SyntaxT3rr0r

La pianificazione della capacità ha un aspetto molto importante: il costo. Se avrai bisogno di X scatole o 2 * X fa un'enorme differenza alla fine. E poiché nessuno può stimare esattamente cosa verrà eseguito in futuro su questi, la soluzione migliore è dare un'occhiata ai diversi carichi di lavoro. Ho controllato alcune implementazioni di questi e li ho trovati per lo più OK. Penso che i risultati possano essere usati come base per le stime.
Agoston Horvath

In generale, i sistemi del mondo reale sono vincolati dall'IO non dalla CPU. Pertanto, se Go è 2x o 5x è più lento, difficilmente fa la differenza nella pianificazione della capacità come failover, bilanciamento del carico, caching, topologia del database e simili. Questo è il motivo per cui le app della scala di YouTube possono permettersi di eseguire molti dei loro sistemi in Python.
Sujoy Gupta

34

La mia risposta non è così tecnica come quella di tutti gli altri, ma penso che sia ancora rilevante. Ho visto gli stessi benchmark sul gioco Computer Benchmarks quando ho deciso di iniziare a imparare Go. Ma onestamente penso che tutti questi benchmark sintetici siano inutili per decidere se Go è abbastanza veloce per te.

Recentemente avevo scritto un server di messaggi in Python usando Tornado + TornadIO + ZMQ e per il mio primo progetto Go ho deciso di riscrivere il server in Go. Finora, avendo portato il server alla stessa funzionalità della versione Python, i miei test mi hanno mostrato un aumento della velocità di 4,7 volte nel programma Go. Intendiamoci, sto codificando in Go solo da forse una settimana e codifico in Python da oltre 5 anni.

Go diventerà sempre più veloce man mano che continuano a lavorarci, e penso che davvero dipenda da come si comporta in un'applicazione del mondo reale e non da piccoli benchmark computazionali. Per me, Go apparentemente ha prodotto un programma più efficiente di quello che potevo produrre in Python. Questa è la mia opinione sulla risposta a questa domanda.


3
Quanto più lentamente pensi di scrivere codice Go rispetto a Python?
Erik Engheim

7
@AdamSmith - Direi che scriverei codice Go più lentamente di Python solo perché codifico Python da oltre 7 anni e solo un po 'Go. Ma in termini di Go rispetto ad altri linguaggi compilati e tipizzati staticamente, scommetto che scriverei Go più velocemente di altri. Personalmente, penso che sia la cosa più vicina alla semplicità di Python con velocità tra C e C ++
jdi

5
Ho una storia simile. Ho appena iniziato a imparare Go e, secondo Benchmarks Game, Go è PIÙ LENTO di JavaScript V8. Risulta che il mio programma che è intenso di operazioni binarie viene eseguito 10 volte più velocemente con codice Go non ottimizzato rispetto a una VM V8 altamente ottimizzata. Go può essere più lento di C in molte operazioni, tuttavia nessuno scrive siti Web in C. Go è già un'opzione perfettamente praticabile e dovrebbe solo migliorare, man mano che vengono visualizzate nuove librerie, framework e strumenti.
se __name__ è Nessuno

1
@ user962247 questa è un'affermazione folle e falsa. Scrivo Go da anni ormai ed è velocissimo. Nessuno afferma che supererà C / C ++ / Java su ogni benchmark sintetico possibile. Ma su alcuni vince (vedi il sito del gioco benchmark). Prendilo da qualcuno che ha effettivamente scritto il codice Go di produzione per anni. È veloce e produttivo.
jdi


6

Le cose sono cambiate.

Penso che l'attuale risposta corretta alla tua domanda sia contestare l'idea che andare è lento. Al momento della tua indagine il tuo giudizio era giustificato, ma da allora il go ha guadagnato molto terreno in termini di prestazioni. Ora, non è ancora veloce come C, ma non è neanche lontanamente 10 volte più lento, in senso generale.

Gioco di benchmark in linguaggio informatico

Al momento della stesura di questo articolo:

source  secs    KB      gz      cpu     cpu load

reverse-complement
1.167x
Go      0.49    88,320  1278    0.84    30% 28% 98% 34%
C gcc   0.42    145,900 812     0.57    0% 26% 20% 100%

pidigits
1.21x
Go      2.10    8,084   603 2.10    0% 100% 1% 1%
C gcc   1.73    1,992   448 1.73    1% 100% 1% 0%

fasta
1.45x
Go      1.97    3,456   1344    5.76    76% 71% 74% 73%
C gcc   1.36    2,800   1993    5.26    96% 97% 100% 97%

regex-dna
1.64x
Go      3.89    369,380 1229    8.29    43% 53% 61% 82%
C gcc   2.43    339,000 2579    5.68    46% 70% 51% 72%

fannkuch-redux
1.72x
Go      15.59   952 900 62.08   100% 100% 100% 100%
C gcc   9.07    1,576   910 35.43   100% 99% 98% 94%

spectral-norm
2x
Go      3.96    2,412   548 15.73   99% 99% 100% 99%
C gcc   1.98    1,776   1139    7.87    99% 99% 100% 99%

n-body
2.27x
Go      21.73   952 1310    21.73   0% 100% 1% 2%
C gcc   9.56    1,000   1490    9.56    1% 100% 1% 1%

k-nucleotide
2.40x
Go      15.48   149,276 1582    54.68   88% 97% 90% 79%
C gcc   6.46    130,076 1500    17.06   51% 37% 89% 88%

mandelbrot
3.19x
Go      5.68    30,756  894 22.56   100% 100% 99% 99%
C gcc   1.78    29,792  911 7.03    100% 99% 99% 98%

Tuttavia, soffre brutalmente sul benchmark dell'albero binario:

binary-trees
12.16x
Go      39.88   361,208 688 152.12  96% 95% 96% 96%
C gcc   3.28    156,780 906 10.12   91% 77% 59% 83%

Ora è alla pari con Java, ma Go non è stato creato esplicitamente per essere più veloce di Java, pur essendo utilizzato per le stesse cose (app di rete lato server)?
MaxB

1
@MaxB no, non è stato creato con l'obiettivo di essere più veloce di Java. È stato creato con l'obiettivo di avere buone prestazioni, compilazione più veloce rispetto al C ++ e concorrenza più semplice e nativa per consentire agli sviluppatori di essere più produttivi. Battere la velocità di runtime di altre lingue non è stato un fattore determinante.
jdi

5

Nonostante l'efficienza non così buona di Go sull'utilizzo dei cicli della CPU, il modello di concorrenza Go è molto più veloce del modello di thread in Java, ad esempio, e può essere paragonabile al modello di thread C ++.

Si noti che nel benchmark thread-ring , Go era 16 volte più veloce di Java. Nello stesso scenario Go CSP era quasi paragonabile a C ++, ma utilizzava 4 volte meno memoria.

Il grande potere del linguaggio Go è il suo modello di concorrenza, Communicating Sequential Processes, CSP, specificato da Tony Hoare negli anni '70, semplice da implementare e adatto a esigenze altamente concorrenti.


2

Ci sono due ragioni fondamentali per cui Java è più veloce di Go e C ++ e può essere più veloce di C in molti casi:

1) Il compilatore JIT. Può inline chiamate di funzioni virtuali attraverso più livelli, anche con classi OO, basate sul profilo di runtime. Ciò non è possibile in un linguaggio compilato staticamente (sebbene la più recente ricompilazione basata sul profilo registrato possa aiutare). Questo è molto importante per la maggior parte dei benchmark che coinvolgono algoritmi ripetitivi.

2) Il GC. L'allocazione della memoria basata su GC è quasi gratuita, rispetto a malloc. E la penalità "gratuita" può essere ammortizzata durante l'intero runtime, spesso saltata perché il programma termina prima che sia necessario raccogliere tutta la spazzatura.

Ci sono centinaia (migliaia?) Di sviluppatori di grande talento che rendono efficiente il GC / JVM. Pensare di poter "programmare meglio di tutti loro" è una follia. È un problema dell'ego umano nel suo cuore: gli umani hanno difficoltà ad accettare che con un addestramento adeguato da parte di esseri umani di talento, il computer funzionerà meglio degli umani che lo hanno programmato.

A proposito, il C ++ può essere veloce come il C se non usi e delle funzionalità OO, ma allora sei abbastanza vicino alla semplice programmazione in C per cominciare.

Soprattutto, le "differenze di velocità" in questi test sono generalmente prive di significato. I costi di I / O sono ordini di grandezza superiori alle differenze di prestazioni, quindi i progetti appropriati che riducono al minimo i costi di I / O hanno sempre la meglio, anche in un linguaggio interpretato. Pochissimi sistemi sono vincolati alla CPU.

Come nota finale, le persone si riferiscono al "gioco dei benchmark del linguaggio del computer" come una "misura scientifica". I test sono completamente difettosi, ad esempio, se visualizzi i test Java per nessuno. Quando eseguo i test sullo stesso sistema operativo / hardware, ottengo circa 7,6 secondi per Java e 4,7 secondi per C - il che è ragionevole - non la lentezza 4x segnalata dai test. È un click-bait, fake news, progettato per generare traffico sul sito.

Come nota finale, finale ... Ho eseguito i test utilizzando Go, ed è stato di 7,9 secondi. Il fatto che quando fai clic su Vai, lo paragoni a Java e quando fai clic su Java lo confronta con C, dovrebbe essere una bandiera rossa per qualsiasi ingegnere serio.

Per un confronto nel mondo reale di Java, Go e C ++, vedere https://www.biorxiv.org/content/10.1101/558056v1 avviso di spoiler, Java è il migliore in termini di prestazioni grezze, con Go che è in cima con l'uso combinato della memoria e tempo di parete.


sbagliato. C ++ È veloce quanto C, specialmente quando usi OOP, questo è il suo certificato di nascita pell. più astrazione (come nelle classi) SENZA ALCUN DEGRADO DELLE PRESTAZIONI A RUNTIME, CON ZERO EXTRA BYTES MEMORY. se non lo sai, continua a giocare con java, c #, go, python, eccetera

// Btw, C ++ può essere veloce come C se non usi e delle funzionalità OO //, ma allora sei abbastanza vicino alla semplice programmazione in C // per cominciare. se lo dici, hai pochissime idee su c ++, per il tuo bene, non usarlo. c e c ++ odiano la magia e le menti medievali, di natura superstiziosa, come oh l'ho sentito, leggilo su Internet, deve essere vero ... stai lontano da c e c ++, ti risponderanno amico mio (consiglio onesto)

c è l'antenato di c ++. molte persone lo usano ancora ... c ++ è un c migliore, dove puoi fare di più senza pagare il prezzo. gli autori java, c # e go non l'hanno capito, beh, certo, l'hanno fatto, ma cosa possono fare?!? lo stesso sull'essere compatibile con il codice (c) esistente. oceani della vita reale di codice c! python è un bel giocattolo, divertiti, vorrei che lo avessero capito bene, ma nah, zen di python avrebbe dovuto iniziare con "il compilatore è tuo amico" ...

>> mostra l'utilizzo della CPU al 30% per il programma Java << No —— "1% 0% 0% 100%".
igouy

1
@igouy Ammetto che questo è un errore che probabilmente ho commesso - quando ho visto load, stavo interpretando in termini di "carico di sistema" e assumendo, user / system / io / idle - il mio errore, ed è stato sostanziale.
robert engels

1

Penso che un fatto spesso trascurato sia che la compilazione JIT può essere> compilazione statica specialmente per funzioni o metodi (runtime) late bound. L'hotspot JIT decide su RUNTIME quali metodi integrare, potrebbe persino adattare il layout dei dati alla dimensione / architettura della cache della CPU su cui è attualmente in esecuzione. C / C ++ in generale può compensare (e nel complesso funzionerà ancora meglio) avendo accesso diretto all'hardware. Per Go le cose potrebbero sembrare diverse in quanto è di livello più alto rispetto a C, ma attualmente manca un sistema / compilatore di ottimizzazione del runtime. Il mio istinto mi dice che Go potrebbe essere più veloce di Java in quanto Go non impone la ricerca del puntatore così tanto e incoraggia una migliore località della struttura dei dati + richiede meno allocazione.


1

È un dato di fatto, Go non è solo elegante ed efficiente in fase di progettazione, ma anche super performante in fase di esecuzione. La chiave è utilizzare il sistema operativo corretto, ovvero LINUX. I risultati del profiling delle prestazioni in Windows e Mac OS sono, in mancanza di una parola migliore, uno o due ordini di grandezza inferiori.


0

sotto Linux, il runtime go è super veloce, perfettamente paragonabile a c / c ++. il runtime go sotto windows e unix non sono nella stessa lega

il confronto con java non è così importante, go è sia per lo sviluppo di sistemi che di applicazioni (poiché java è più simile a un colletto blu solo per lo sviluppo di applicazioni). non entrerà nei dettagli, ma quando cose come kubernetes sono scritte in go, ti rendi conto che non è un giocattolo amichevole per i consulenti aziendali

Non ricordo che Google abbia menzionato nemmeno una volta il compromesso a cui ti riferisci. go è ben progettato, semplice, elegante ed efficiente per la progettazione di programmi a livello di sistema e applicazione, ha puntatori, allocazione efficiente della memoria e deallocazione, evita complicazioni derivanti da un'eredità di implementazione così facile da usare, dandoti co-routine e altre moderne modi per scrivere applicazioni ad alte prestazioni in tempi e budget. di nuovo, go è super veloce sotto Linux, che è esattamente quello per cui è stato progettato (molto felice che lo faccia)


-4

Sia Java che C sono più espliciti con i loro dati e le definizioni di metodo (funzione). C è tipizzato staticamente e Java lo è meno con il suo modello di ereditarietà. Ciò significa che il modo in cui i dati verranno gestiti è praticamente definito durante la compilazione.

Go è più implicito con i suoi dati e le definizioni delle funzioni. Le funzioni integrate sono di natura più generale e la mancanza di una gerarchia di tipi (come Java o C ++) conferisce a Go uno svantaggio di velocità.

Tieni presente che l'obiettivo di Google per il linguaggio Go è di avere un compromesso accettabile tra velocità di esecuzione e velocità di codifica. Penso che stiano raggiungendo un buon punto debole nel loro primo tentativo e le cose miglioreranno solo con il lavoro svolto.

Se confronti Go con linguaggi più tipizzati dinamicamente il cui vantaggio principale è la velocità di codifica, vedrai il vantaggio della velocità di esecuzione di Go. Go è 8 volte più veloce di perl e 6 volte più veloce di Ruby 1.9 e Python 3 su quei benchmark che hai usato.

Comunque la domanda migliore da porre è Go: un buon compromesso tra facilità di programmazione e velocità di esecuzione? La mia risposta è sì e dovrebbe migliorare.


20
"la mancanza di una gerarchia di tipi (come Java o C ++) dà a Go uno svantaggio di velocità" —wut?
Erik Kaplun

6
"Go è più implicito con i suoi dati e le definizioni delle funzioni." Non corretto. Intendi dire come i tipi possono implementare metodi senza essere espliciti al riguardo? Il compilatore rileva l'appartenenza all'interfaccia di tipo. Questo è veloce. "Le funzioni integrate sono di natura più generale" no, le funzioni predefinite sono, come tutto il resto, compilate. La stessa cosa accade con i modelli C ++. "La mancanza di una gerarchia di tipi (come Java o C ++) conferisce a Go uno svantaggio di velocità" - non corretto, una gerarchia di tipi non ha nulla a che fare con l'esecuzione in runtime.
Malcolm
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.