34 Stimmen

Warum ist Erlang bei all diesen kleinen Mathe-Benchmarks langsamer als Java?

Bei der Suche nach Alternativen zu Java für eine verteilte/gleichzeitige/ausfallsichere/skalierbare Backend-Umgebung entdeckte ich Erlang. Ich habe einige Zeit mit Büchern und Artikeln verbracht, in denen fast alle (sogar Java-begeisterte Leute) sagen, dass Erlang in solchen Umgebungen die bessere Wahl ist, da viele nützliche Dinge auf eine weniger fehleranfällige Art und Weise sofort einsatzbereit sind.

Ich war mir sicher, dass Erlang in den meisten Fällen schneller ist, hauptsächlich wegen einer anderen Garbage-Collection-Strategie (pro Prozess), dem Fehlen eines gemeinsamen Zustands (zwischen Threads und Prozessen) und kompakteren Datentypen. Aber ich war sehr überrascht, als ich fand Vergleich von Erlang- und Java-Mathematikbeispielen wobei Erlang um mehrere Größenordnungen langsamer ist, z. B. von x10 bis x100.

Auch bei gleichzeitigen Aufgaben, sowohl auf mehreren Kernen als auch auf einem einzigen.

Was sind die Gründe dafür? Diese Antworten kamen mir in den Sinn:

  • Verwendung von Java-Primitiven (=> kein Heap/gc) bei den meisten Aufgaben
  • Gleiche Anzahl von Threads in Java-Code und Erlang-Prozessen, so dass das Akteursmodell hier keinen Vorteil hat
  • Oder einfach nur, dass Java statisch typisiert ist, während Erlang nicht typisiert ist.
  • Etwas anderes?

Wenn das daran liegt, dass es sich um sehr spezifische mathematische Algorithmen handelt, kann dann jemand mehr reale/praktische Leistungstests zeigen?

UPDATE: Ich habe die Antworten so weit zusammenfassen, dass Erlang ist nicht das richtige Werkzeug für solche spezifischen "schnelle Java Fall", aber die Sache, die mir unklar ist - was ist der Hauptgrund für solche Erlang Ineffizienz hier: dynamische Typisierung, GC oder schlechte native Kompilierung?

34voto

npe Punkte 15205

Erlang wurde nicht für Mathematik entwickelt. Es wurde mit Blick auf Kommunikation, Parallelverarbeitung und Skalierbarkeit entwickelt. Es für mathematische Aufgaben zu testen, ist also ein bisschen so, als würde man testen, ob der Presslufthammer einem eine erfrischende Massage beschert.

Aber lassen Sie uns ein wenig ausholen:
Wenn Sie in der JVM im Stil von Erlang programmieren wollen, schauen Sie sich Scala-Akteure o Akka-Framework o Vert.x .

15voto

Emil Vikström Punkte 87499

Benchmarks sind nie dazu geeignet, etwas anderes zu sagen als das, was sie wirklich testen. Wenn Sie das Gefühl haben, dass ein Benchmark nur Primitive und ein klassisches Threading-Modell testet, dann ist es das, worüber Sie Wissen erhalten. Sie können nun mit einiger Sicherheit sagen, dass Java in der Mathematik bei Primitiven und dem klassischen Threading-Modell für diese Art von Problemen schneller ist als Erlang. Sie wissen nichts über die Leistung bei einer großen Anzahl von Threads oder bei komplexeren Problemen, da der Benchmark dies nicht getestet hat.

Wenn Sie die im Benchmark getestete Art von Mathematik betreiben, sollten Sie Java verwenden, da es offensichtlich das richtige Werkzeug für diese Aufgabe ist. Wenn Sie etwas stark skalierbares mit wenig bis gar keinem gemeinsamen Zustand machen wollen, sollten Sie einen Benchmark dafür finden oder zumindest Erlang neu bewerten.

Wenn Sie in Erlang wirklich viel rechnen müssen, sollten Sie HiPE in Betracht ziehen (oder es überhaupt in Betracht ziehen).

8voto

stemm Punkte 5890

Wie bereits in anderen Antworten erwähnt, wurde Erlang entwickelt, um effektiv reale Probleme zu lösen, die den Benchmark-Problemen etwas entgegengesetzt sind.

Aber ich möchte noch einen weiteren Aspekt beleuchten - die Prägnanz des Erlang-Codes (in einigen Fällen bedeutet dies auch die Schnelligkeit der Entwicklung), die sich nach dem Vergleich von Benchmark-Implementierungen leicht feststellen lässt.

Zum Beispiel der k-Nukleotid-Benchmark:
Erlang-Version: http://benchmarksgame.alioth.debian.org/u64q/program.php?test=knucleotide&lang=hipe&id=3
Java-Version: http://benchmarksgame.alioth.debian.org/u64q/program.php?test=knucleotide&lang=java&id=3

Wenn Sie mehr Benchmarks aus dem wirklichen Leben wollen, empfehle ich Ihnen Vergleich von C++ und Erlang für Motorola Telecoms Software

8voto

Vans S Punkte 1648

Ich habe mich dafür interessiert, da einige der Benchmarks perfekt für Erlang geeignet sind, z. B. die Gensequenzierung. Also auf http://benchmarksgame.alioth.debian.org/ Als erstes habe ich mir die Implementierungen der Rückwärtskomplementierung sowohl für C als auch für Erlang sowie die Testdetails angesehen. Ich fand heraus, dass der Test voreingenommen ist, weil er nicht die Zeit berücksichtigt, die Erlang braucht, um die VM /w die Scheduler zu starten, nativ kompiliertes C wird viel schneller gestartet. Die Art und Weise, wie diese Benchmarks messen, ist grundsätzlich: time erl -noshell -s revcomp5 main < revcomp-input.txt

Jetzt sagt der Benchmark, dass Java 1,4 Sekunden und Erlang /w HiPE 11 Sekunden brauchte. Für die Ausführung des (Single threaded) Erlang-Codes benötigte ich 0,15 Sekunden, und wenn man die Zeit abzieht, die zum Starten des vm benötigt wurde, dauerte die tatsächliche Arbeitslast nur 3000 Mikrosekunden (0,003 Sekunden).

Ich habe also keine Ahnung, wie das bewertet wird, wenn es 100 Mal gemacht wird, dann macht es keinen Sinn, da die Kosten für das Starten der Erlang-VM x100 sein werden. Wenn die Eingabe viel länger ist als angegeben, würde es Sinn machen, aber ich sehe keine Details auf der Webseite dazu. Um die Benchmarks für verwaltete Sprachen fairer zu machen, sollte der Code (Erlang/Java) ein Unix-Signal an Python (das den Benchmark durchführt) senden, dass er die Startup-Funktion getroffen hat.

Abgesehen vom Benchmark führt die Erlang-VM am Ende im Wesentlichen nur Maschinencode aus, ebenso wie die Java-VM. Es gibt also keine Möglichkeit, dass eine mathematische Operation in Erlang länger dauern würde als in Java.

Was Erlang nicht kann, sind Daten, die sich häufig ändern müssen. Wie zum Beispiel eine verkettete Blockchiffre. Sagen wir, Sie haben die Zeichen "0123456789", jetzt Ihre Verschlüsselung xors die ersten 2 Zeichen durch 7, dann xors die nächsten zwei Zeichen durch das Ergebnis der ersten beiden addiert, dann xors die vorherigen 2 Zeichen durch die Ergebnisse der aktuellen 2 subtrahiert, dann xors die nächsten 4 Zeichen etc

Da Objekte in Erlang unveränderlich sind, bedeutet dies, dass das gesamte char-Array jedes Mal kopiert werden muss, wenn es verändert wird. Deshalb hat Erlang Unterstützung für Dinge namens NIFS, das ist C-Code, den man aufrufen kann, um genau dieses Problem zu lösen. In der Tat alle die Verschlüsselung (ssl, aes, blowfish..) und Kompression (zlib,..), die mit Erlang geliefert werden, sind in C implementiert, auch gibt es in der Nähe von 0 Kosten mit dem Aufruf von C aus Erlang verbunden.

Mit Erlang erhalten Sie also das Beste aus beiden Welten, Sie erhalten die Geschwindigkeit von C mit der Parallelität von Erlang.

Wenn ich die Rückwärtskomplementierung auf die SCHNELLSTMÖGLICHE Art und Weise implementieren wollte, würde ich den mutierenden Code in C, den parallelen Code aber in Erlang schreiben. Unter der Annahme, dass die Eingabe unendlich ist, würde ich Erlang auf die > <<Line/binary, ">", Rest/binary>> = read_stream Übergabe des Blocks an den ersten verfügbaren Scheduler per Round-Robin-Verfahren, bestehend aus unendlich vielen privaten vernetzten EC2-Hidden Nodes, die dem Cluster jede Millisekunde in Echtzeit hinzugefügt werden.

Diese Knoten rufen dann über NIFS C zur Verarbeitung auf (C war die schnellste Implementierung für Reverse-Compliment auf der alioth-Website) und senden dann die Ausgabe zurück an den Knoten-Master, der sie an den Eingabecomputer sendet.

Um all dies in Erlang zu implementieren, müsste ich den Code so schreiben, als ob ich ein Programm mit nur einem Thread schreiben würde, und es würde weniger als einen Tag dauern, diesen Code zu erstellen.

Um dies in Java zu implementieren, müsste ich den Single-Thread-Code schreiben, ich müsste die Leistungseinbußen durch den Aufruf von Managed zu Unmanaged in Kauf nehmen (da wir die C-Implementierung für die Routinearbeit verwenden werden), und ihn dann umschreiben, um 64 Kerne zu unterstützen. Dann neu schreiben, um mehrere CPUS zu unterstützen. Dann schreiben Sie es erneut um, um Clustering zu unterstützen. Dann wieder neu schreiben, um Speicherprobleme zu beheben.

Und das ist Erlang in einer Nussschale.

3voto

pmarreck Punkte 180

Die Erlang-Lösung verwendet ETS, Erlang Term Storage, das wie eine In-Memory-Datenbank in einem separaten Prozess läuft. Da sie sich in einem separaten Prozess befindet, müssen alle Nachrichten an und von diesem Prozess serialisiert/deserialisiert werden. Dies würde einen Großteil der Langsamkeit erklären, sollte ich meinen. Wenn Sie sich zum Beispiel den "regex-dna"-Benchmark ansehen, ist Erlang dort nur geringfügig langsamer als Java, und es verwendet kein ETS.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X