2010-08-20 19 views
9

Oggi stavo facendo l'esercizio con anello di filo dal Programmazione Erlang e cercato su Google altre soluzioni da confrontare. Ho scoperto che la sparatoria in lingua ha esattamente lo stesso problema di benchmark. Ho avuto l'impressione che questa sia un'area in cui Erlang dovrebbe essere veloce, ma scopre che C e C++ sono di nuovo in cima. Il mio sospetto è che i programmi C/C++ non stiano seguendo le regole che dicono "passare il token da thread a thread". Sembra, dopo averli letti, che entrambi manipolino parte della memoria condivisa e delle variabili globali che è diversa dal codice di Erlang, ma potrei sbagliarmi.Riferimento anello filettatura

La mia domanda è: stanno facendo la stessa cosa o il codice C/C++ è concettualmente diverso (e più veloce) da quello di Erlang?

E un'altra domanda: perché Haskell è più veloce di Erlang quando le soluzioni sono molto simili?

+2

Alcuni di questi confronti sono quelli di mele e arance. La ragione di questo è che se vuoi solo che le cose vadano in giro molto velocemente, allora puoi farlo molto più velocemente in C e C++. Il punto IMHO è che Erlang gestisce molto di più che semplicemente "inviando un token tra processi" (si tratta di processi che non sono thread;)). Ho scritto un articolo su alcune delle differenze un po 'di tempo fa; vale la pena di verificare: http://forum.trapexit.org/viewtopic.php?t=15194 e http://www.trapexit.org/Process_Ring_Across_Nodes –

+0

Questo è un buon esempio e la definizione che stai dando è qualcosa che mi aspetterei da tutte le soluzioni. Qualcuno ha provato a riscriverlo in un'altra lingua, a qualche risultato? Inoltre, puoi pensare ad un benchmark single-node in cui Erlang potrebbe eccellere in termini di velocità? –

+1

Il punto che Joe Armstrong stava facendo era semplicemente "Il passaggio dei messaggi tra i processi dormienti in Erlang è molto veloce ... Java è da 5 a 10 volte più lento." (I programmatori Java hanno ridotto tale differenza.) [Misurazioni delle prestazioni dei thread in Java e nei processi in Erlang 1998-11-02] – igouy

risposta

6

In definitiva, il trasferimento di messaggi su macchine moderne viene implementato utilizzando una qualche forma di memoria condivisa per passare i messaggi (insieme a serrature o istruzioni atomiche). Quindi tutte le implementazioni di C e C++ stanno davvero facendo sta integrando l'implementazione del passaggio dei messaggi direttamente nel loro codice. Un benchmark simile che utilizza una libreria di passaggio rapido dei messaggi in C, anch'essa confrontata con Haskell ed Erlang, può essere trovato in questo documento: http://www.cs.kent.ac.uk/pubs/2009/2928/index.html (sezione 5.1)

La velocità dei vari approcci è realmente determinata dalla corsa concorrente -time sistemi coinvolti. Haskell ha svolto un ottimo lavoro in quest'area, che lo lascia davanti a Erlang. Ovviamente, misurare la velocità su micro-benchmark è spesso fuorviante e lascia fuori fattori importanti come la leggibilità del codice. Una domanda da tenere a mente potrebbe essere: quale delle soluzioni negli shoot-out vorresti mantenere?

+2

dipende da quale si guadagna di più :) – Tom

+0

>> Naturalmente, misurare la velocità su micro-benchmark è spesso fuorviante e lascia fuori fattori importanti come la leggibilità del codice. << Questo è uno dei motivi per cui il gioco di benchmark mostra il codice sorgente del programma ;-) – igouy

9

La versione C utilizza LWP, che a mio avviso è una libreria di threading dello spazio utente. Fino a che punto questo è "ingiusto" è in discussione: guarderei cose come se supporta una reale concorrenza preventiva nel senso che è possibile effettuare chiamate di sistema bloccanti in un thread senza bloccare tutti gli altri thread (è possibile fai questo in Haskell, puoi farlo ad Erlang?).

I thread di Haskell sono leggermente più leggeri di quelli di Erlang, perché, a quanto ho capito, un thread di Erlang viene fornito con un heap locale (nell'implementazione standard) mentre i thread Haskell condividono tutti lo stesso heap.

+0

Qual è il sovraccarico della memoria di un thread Haskell (GHC)? –

+0

Minimo. È possibile creare migliaia di thread senza incorrere in problemi di memoria. – jrockway

+0

Quanto, confrontato con i 300 byte di Erlang? –

5

Non credo di chiamarlo barare. La principale, fondamentale differenza tra più thread e più processi è che più thread condividono un singolo spazio di indirizzamento. In quanto tale, la definizione di più thread (anziché di più processi) mi sembra un tacito permesso di sfruttare lo spazio di indirizzamento condiviso (almeno in assenza di una definizione molto specifica di "passing" che lo proibiva).

Ciò che viene in mente è questo: Erlang in realtà non ha thread, in quanto tale - ha processi con comunicazioni asincrone. I processi sono (intenzionalmente) isolati l'uno dall'altro in larga misura. Da un lato, questo rende lo sviluppo molto più facile - in particolare, un processo può influenzare solo un altro tramite canali di comunicazione specifici e ben definiti. Sotto il cofano, utilizza molti trucchi (quasi certamente includendo la memoria condivisa) per ottimizzare i suoi processi e trarre vantaggio da ciò che è possibile in una specifica implementazione/situazione (come tutti i processi in esecuzione in un unico spazio di indirizzamento condiviso). Ciò nonostante, il fatto di dover mantenere nascosti tutti i trucchi impedisce di essere altrettanto efficiente di qualcosa come la versione C in cui i "trucchi" sono tutti espliciti e completamente esposti.

Vorrei usare un'analogia della vita reale per spiegare la differenza. Pensa ai thread/processi come persone.Erlang impone un rapporto professionale di lavoro in cui le comunicazioni sono tutte accuratamente registrate nei memo. Le versioni C e C++ sono più simili a un marito e una moglie che potrebbero comunicare con una singola parola che non significa nulla per nessuno, o anche solo una rapida occhiata.

Quest'ultimo è estremamente efficiente quando funziona, ma è molto più aperto a sottili incomprensioni, e se i due litigano probabilmente non vorrai essere nella stessa stanza. Per il manager, le persone in relazioni puramente professionali sono molto più facili da gestire anche se la loro massima efficienza non è abbastanza alta.

2

non seguendo le regole

dato quanti davvero molto diversi approcci ci sono a concorrenza di programmazione, ho trovato molto difficile sia essere abbastanza inclusiva per portare in diverse implementazioni lingua e tuttavia mantenere una certa comparabilità vaga.

Ora guardate le prestazioni degli stessi programmi misurati con different run time configuration e notare quanto che conta -

SMP quad core 
1.0 C GNU gcC#3 4.16 4.17 16,952 607 100% 0% 1% 0% 
4.2 Haskell GHC  17.99 17.42 4,020 307 100% 1% 1% 1% 
7.5 Erlang HiPE  31.12 31.13 10,504 273 0% 0% 0% 100% 

No SMP one core 
1.0 C GNU gcC#3 4.16 4.16 16,952 607 1% 0% 0% 100% 
1.4 Haskell GHC  5.89 5.89 3,204 307 0% 0% 0% 100% 
2.6 Erlang HiPE  10.64 10.63 9,276 273 0% 0% 0% 100% 
+0

Che ne dici di richiedere l'utilizzo di un'astrazione di thread completamente preventiva? (nessun thread può impedire ad altri di progredire) –

+0

Senza considerare se sarebbe una "cosa buona" quale dei primi 10 programmi sarebbe escluso? – igouy

+0

Per quanto riguarda i 4 risultati core più lenti per GHC, è possibile utilizzare l'affinità del processore per migliorarlo? –

4

perché è più veloce di Haskell Erlang quando la soluzione sono molto simili?

Haskell GHC è un'implementazione linguistica ottimizzata e nativa con thread molto veloci. In genere è molto più veloce di Erlang/HIPE. Erlang non ha il monopolio sui fili leggeri :-)

4

Vorrei rispondere con un'altra domanda: come è implementato il runtime Erlang sotto il cofano?

È probabile che sia implementato in C o in un linguaggio di sistema simile (dubito che abbiano fatto tutto in assembly). O per lo meno, che i concetti che esprimono possono essere espressi in modo efficiente in C.

Ora, perché trovi così strano che una versione C ottimizzata (lo shootout di certo non mostri il codice di livello medio) batterebbe la versione di Erlang, considerando che Erlang aggiunge il proprio livello di complessità/indirezione?

Qualunque sia il tipo di benchmark, è sempre possibile che un'implementazione C superi il programma più lucido in un'altra lingua ... costruita sopra C, semplicemente perché si prende la versione C che genera e quindi si rimuovono i bit che non hai bisogno.

D'altra parte:

  • quanto tempo hai impiegato a scrivere il codice?
  • qual è il tuo grado di fiducia che fa la cosa giusta? non si bloccherà?
  • quale preferiresti mantenere?

A volte "più veloce" non vale il costo.

+0

Sì, quella era la mia domanda, se le diverse soluzioni sono allo stesso livello di astrazione. Penso che siamo tutti d'accordo sul fatto che non sono in questo caso. Per quanto riguarda le tue domande - sicuramente non i programmi C/C++. –

1

Una cosa da notare in questo benchmark è che c'è un solo token da passare. Ciò significa che in pratica è solo un programma a thread singolo che legge e scrive dalla/alla memoria.

Mi aspetto che il risultato diventi diverso su un computer multiprocessore (o lo faccia un cluster) in cui i thread/processi devono passare i token M in giro in un ordine casuale.

Hmm. Dare anche agli sviluppatori 'delle soluzioni di riferimento un numero uguale di ore per completare la loro soluzione. Quindi mi aspetterei che Erlang esca in cima (o almeno in alto).

+0

"Una cosa da notare" +1 "Allora mi aspetterei" -1 – igouy

+0

Probabilmente hai ragione. Questo sta assumendo un po 'troppo. Grazie per il tuo commento. –

+0

"I benchmark che possono sembrare concomitanti sono spesso sequenziali. Il benchmark di estone, ad esempio, è interamente sequenziale. Quindi è anche l'implementazione più comune del "ring benchmark"; di solito un processo è attivo, mentre gli altri aspettano in una dichiarazione di ricezione. ' http://www.erlang.org/doc/efficiency_guide/processes.html#id66266 – igouy