Manchmal übertrifft Java C ++ in Benchmarks. Natürlich übertrifft C ++ manchmal.
Siehe die folgenden Links:
- http://keithlea.com/javabench/
- http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy/
- http://blog.cfelde.com/2010/06/c-vs-java-performance/
Aber wie ist das überhaupt möglich? Es verwirrt mich, dass interpretierter Bytecode jemals schneller sein könnte als eine kompilierte Sprache.
Kann jemand bitte erklären? Vielen Dank!
java
c++
performance
Deets McGeets
quelle
quelle
Antworten:
Erstens enthalten die meisten JVMs einen Compiler, so dass "interpretierter Bytecode" eigentlich ziemlich selten ist (zumindest im Benchmark-Code - es ist nicht ganz so selten im wirklichen Leben, wo Ihr Code normalerweise mehr als ein paar unbedeutende Schleifen enthält, die extrem oft wiederholt werden ).
Zweitens scheint eine ganze Reihe von Benchmarks ziemlich voreingenommen zu sein (ob absichtlich oder inkompetent, kann ich nicht wirklich sagen). Zum Beispiel habe ich mir vor Jahren einen Teil des Quellcodes angesehen, der über einen der von Ihnen geposteten Links verlinkt wurde. Es hatte Code wie folgt:
Da
calloc
der Speicher bereits auf Null gesetzt ist, ist die Verwendung derfor
Schleife auf Null offensichtlich unbrauchbar. Daraufhin wurde der Speicher (sofern der Speicher belegt ist) ohnehin mit anderen Daten gefüllt (und es bestand keine Abhängigkeit davon, dass sie auf Null gesetzt wurden), sodass das gesamte Nullsetzen ohnehin völlig unnötig war. Das Ersetzen des obigen Codes durch einen einfachen Codemalloc
(wie es jede vernünftige Person zu Beginn getan hätte) verbesserte die Geschwindigkeit der C ++ - Version so weit, dass sie die Java-Version übertraf (bei ausreichendem Speicherplatz).Betrachten Sie (für ein anderes Beispiel) den
methcall
Benchmark, der im Blogeintrag in Ihrem letzten Link verwendet wurde. Ungeachtet des Namens (und wie die Dinge vielleicht sogar aussehen) ist die C ++ - Version davon überhaupt nicht sehr an Methodenaufruf-Overhead interessiert. Der Teil des Codes, der sich als kritisch herausstellt, befindet sich in der Toggle-Klasse:Der kritische Teil ist der
state = !state;
. Überlegen Sie, was passiert, wenn wir den Code ändern, um den Status alsint
statt als zu codierenbool
:Diese geringfügige Änderung verbessert die Gesamtgeschwindigkeit um etwa 5: 1 . Obwohl der Benchmark die Methodenaufrufzeit messen sollte, war der größte Teil der Zeit, die gemessen wurde, die Zeit, zwischen
int
und umzurechnenbool
. Ich würde mit Sicherheit zustimmen, dass die Ineffizienz, die das Original zeigt, bedauerlich ist - aber angesichts der Tatsache, wie selten es in echtem Code vorkommt und mit welcher Leichtigkeit es behoben werden kann, wenn / wenn es auftritt, fällt es mir schwer, nachzudenken davon als viel zu bedeuten.Falls sich jemand entscheidet, die betroffenen Benchmarks erneut auszuführen, sollte ich auch hinzufügen, dass die Java-Version, die produziert wird (oder zumindest einmal produziert wurde - ich habe die Tests mit a nicht erneut ausgeführt), eine fast ebenso triviale Änderung aufweist Jüngste JVMs bestätigen, dass sie dies immer noch tun. Auch in der Java-Version ist dies eine ziemlich wesentliche Verbesserung. Die Java-Version hat ein NthToggle :: activate (), das so aussieht:
Wenn Sie dies ändern, um die Basisfunktion aufzurufen, anstatt
this.state
direkt zu manipulieren, wird die Geschwindigkeit erheblich verbessert (obwohl dies nicht ausreicht, um mit der modifizierten C ++ - Version Schritt zu halten).Also, was wir am Ende haben, ist eine falsche Annahme über interpretierte Bytecodes im Vergleich zu einigen der schlechtesten Benchmarks (die ich je gesehen habe). Weder gibt ein aussagekräftiges Ergebnis.
Meine eigene Erfahrung ist, dass C ++ mit ebenso erfahrenen Programmierern, die gleichermaßen auf die Optimierung achten, Java häufiger schlagen wird als nicht - aber (zumindest zwischen diesen beiden) wird die Sprache selten so viel Unterschied machen wie die Programmierer und das Design. Die angeführten Benchmarks sagen mehr über die (In-) Kompetenz / (Dis-) Ehrlichkeit ihrer Autoren aus als über die Sprachen, die sie als Benchmark angeben.
[Bearbeiten: Wie oben an einer Stelle angedeutet, aber nie so direkt angegeben, wie ich es wahrscheinlich hätte tun sollen, sind die Ergebnisse, die ich erhalten habe, als ich dies vor ~ 5 Jahren mit C ++ - und Java-Implementierungen getestet habe, die zu dieser Zeit aktuell waren . Ich habe die Tests mit den aktuellen Implementierungen nicht wiederholt. Ein Blick zeigt jedoch, dass der Code noch nicht repariert wurde. Alles, was sich geändert hätte, wäre die Fähigkeit des Compilers, die Probleme im Code zu vertuschen.]
Wenn wir die Java Beispiele ignorieren, aber es ist tatsächlich möglich , interpretierten Code , schneller zu laufen als kompilierten Code (wenn auch schwierig und etwas ungewöhnlich).
In der Regel ist der zu interpretierende Code viel kompakter als der Maschinencode, oder er wird auf einer CPU ausgeführt, die einen größeren Daten-Cache als der Code-Cache hat.
In einem solchen Fall kann ein kleiner Interpreter (z. B. der innere Interpreter einer Forth-Implementierung) vollständig in den Code-Cache passen, und das Programm, das er interpretiert, passt vollständig in den Daten-Cache. Der Cache ist in der Regel mindestens um den Faktor 10 schneller als der Hauptspeicher und häufig um ein Vielfaches schneller (ein Faktor 100 ist nicht mehr besonders selten).
Wenn der Cache also um den Faktor N schneller als der Hauptspeicher ist und weniger als N Maschinencodeanweisungen erforderlich sind, um jeden Bytecode zu implementieren, sollte der Bytecode gewinnen (ich vereinfache, aber ich denke, die allgemeine Idee sollte es trotzdem sein offensichtlich sein).
quelle
Handgerolltes C / C ++ , das von einem Experten mit unbegrenzter Zeit ausgeführt wird, ist mindestens so schnell oder schneller als Java. Letztendlich ist Java selbst in C / C ++ geschrieben, so dass Sie natürlich alles tun können, was Java tut, wenn Sie bereit sind, genügend Engineering-Aufwand zu betreiben.
In der Praxis wird Java jedoch häufig aus folgenden Gründen sehr schnell ausgeführt:
Gleichzeitig hat C / C ++ auch einige Vorteile:
Insgesamt:
quelle
Die Java - Runtime - isnt Bytecode interpretiert. Vielmehr wird das verwendet, was als Just In Time Compilation bezeichnet wird . Grundsätzlich benötigt das Programm beim Ausführen Bytecode und konvertiert ihn in systemeigenen Code, der für die jeweilige CPU optimiert ist.
quelle
Wenn alle Dinge gleich sind, könnte man sagen: Nein, Java sollte niemals schneller sein . Sie könnten Java immer von Grund auf in C ++ implementieren und dadurch mindestens so gute Leistung erzielen. In der Praxis jedoch:
Nebenbei erinnert mich das an die Debatte um C in den 80er / 90er Jahren. Alle fragten sich: "Kann C jemals so schnell sein wie die Montage?" Grundsätzlich lautete die Antwort: Nein auf dem Papier, aber in Wirklichkeit hat der C-Compiler effizienteren Code erstellt als 90% der Assembly-Programmierer (na ja, nachdem er ein bisschen gereift war).
quelle
http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html
quelle
Während ein vollständig optimiertes Java-Programm ein vollständig optimiertes C ++ - Programm selten übertrifft, können Unterschiede in Sachen Speicherverwaltung viele in Java idiomatisch implementierte Algorithmen schneller machen als dieselben in C ++ idiomatisch implementierten Algorithmen.
Wie @Jerry Coffin betonte, gibt es viele Fälle, in denen einfache Änderungen den Code viel schneller machen können - aber oft sind zu viele unsaubere Anpassungen in der einen oder anderen Sprache erforderlich, damit sich die Leistungsverbesserung lohnt. Das ist wahrscheinlich das, was Sie in einem guten Benchmark sehen würden, der zeigt, dass Java besser abschneidet als C ++.
Auch wenn es normalerweise nicht so wichtig ist, gibt es einige Leistungsoptimierungen, die eine JIT-Sprache wie Java nicht in C ++ durchführen kann. Die Java-Laufzeit kann Verbesserungen enthalten, nachdem der Code kompiliert wurde. Dies bedeutet, dass die JIT möglicherweise optimierten Code erstellen kann, um neue (oder zumindest andere) CPU-Funktionen zu nutzen. Aus diesem Grund kann eine 10 Jahre alte Java-Binärdatei möglicherweise eine 10 Jahre alte C ++ - Binärdatei übertreffen.
Schließlich kann die vollständige Typensicherheit im Großen und Ganzen in sehr seltenen Fällen zu extremen Leistungsverbesserungen führen. Singularity , ein experimentelles Betriebssystem, das fast ausschließlich in einer C # -basierten Sprache geschrieben ist, ermöglicht eine viel schnellere Interprozesskommunikation und Multitasking, da keine Hardware-Prozessgrenzen oder teuren Kontextwechsel erforderlich sind.
quelle
Gepostet von Tim Holloway auf JavaRanch:
Quelle: http://www.coderanch.com/t/547458/Performance/java/Ahead-Time-vs-Just-time
quelle
Dies liegt daran, dass der letzte Schritt zum Generieren von Maschinencode transparent in der JVM erfolgt, wenn Sie Ihr Java-Programm ausführen, und nicht explizit, wenn Sie Ihr C ++ - Programm erstellen.
Sie sollten die Tatsache berücksichtigen, dass moderne JVMs ziemlich viel Zeit damit verbringen, den Bytecode im laufenden Betrieb zu nativem Maschinencode zu kompilieren, um ihn so schnell wie möglich zu machen. Auf diese Weise kann die JVM alle Arten von Compilertricks ausführen, die noch besser sind, wenn die Profildaten des ausgeführten Programms bekannt sind.
So etwas wie das automatische Inlinen eines Getters, damit kein JUMP-RETURN erforderlich ist, um nur einen Wert zu erhalten, beschleunigt die Dinge.
Das, was wirklich schnelle Programme ermöglicht hat, ist, danach besser aufzuräumen. Der Speicherbereinigungsmechanismus in Java ist schneller als der manuelle Speicherbereinigungsmechanismus in C. Viele moderne Speicherbereinigungsimplementierungen ohne Speicherbereinigung verwenden einen Speicherbereinigungsmechanismus darunter.
quelle
Kurze Antwort - ist es nicht. Vergiss es, das Thema ist so alt wie Feuer oder Rad. Java oder .NET ist und bleibt nicht schneller als C / C ++. Es ist schnell genug für die meisten Aufgaben, bei denen Sie überhaupt nicht an Optimierung denken müssen. Wie Formulare und SQL-Verarbeitung, aber hier endet es.
Für Benchmarks oder kleine Apps, die von inkompetenten Entwicklern geschrieben wurden, ist das Endergebnis, dass Java / .NET wahrscheinlich in der Nähe und vielleicht sogar noch schneller sein wird.
In der Realität wird Java / .NET durch einfache Dinge wie das Zuweisen von Arbeitsspeicher auf dem Stapel oder die Verwendung von Memzonen sofort beendet.
Garbage Collected World verwendet eine Art Memzone für die gesamte Buchhaltung. Füge memzone zu C hinzu und C wird direkt vor Ort schneller sein. Speziell für die Java vs. C "Hochleistungscode" Benchmarks, die so aussehen:
Versuchen Sie, stapelbasierte Variablen in C / C ++ zu verwenden (oder neu zu platzieren). Sie werden übersetzt in
sub esp, 0xff
eine einzelne x86-Anweisung, die Sie mit Java nicht übertreffen können.Die meiste Zeit sehe ich die Bänke, auf denen Java gegen C ++ verglichen wird. Falsche Speicherzuweisungsstrategien, selbstwachsende Container ohne Reserven, mehrere neue. Dies kommt dem leistungsorientierten C / C ++ - Code nicht einmal nahe.
Lesen Sie auch Folgendes : https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf
quelle
Die Realität ist, dass beide nur hochrangige Assembler sind, die genau das tun, was der Programmierer ihnen befiehlt, genau so, wie der Programmierer es ihnen befiehlt, in der genauen Reihenfolge, in der der Programmierer es ihnen befiehlt. Die Leistungsunterschiede sind so gering, dass sie für alle praktischen Zwecke unerheblich sind.
Die Sprache ist nicht "langsam", der Programmierer hat ein langsames Programm geschrieben. Sehr selten wird ein Programm, das in einer Sprache am besten geschrieben ist, besser sein als ein Programm (zu irgendeinem praktischen Zweck), bei dem das Gleiche auf die beste Art und Weise der alternativen Sprache getan wird, es sei denn, der Autor der Studie ist bestrebt, seine spezielle Axt zu schleifen.
Wenn Sie sich in seltenen Fällen wie Echtzeit-Embedded-Systemen befinden, kann die Sprachauswahl natürlich einen Unterschied machen. Aber wie oft ist dies der Fall? und von diesen Fällen ist, wie oft die richtige Wahl nicht blind offensichtlich.
quelle
Keith Lea sagt, dass es "offensichtliche Mängel" gibt, unternimmt aber nichts gegen diese "offensichtlichen Mängel". Im Jahr 2005 wurden diese alten Aufgaben verworfen und durch die Aufgaben ersetzt, die jetzt im Benchmarks-Spiel angezeigt werden .
Keith Lea sagt, dass er "den Benchmark-Code für C ++ und Java aus dem mittlerweile veralteten Great Computer Language Shootout genommen und die Tests durchgeführt hat", aber tatsächlich zeigt er nur Messungen für 14 von 25 dieser veralteten Tests an .
Keith Lea sagt Ihnen jetzt, dass er vor sieben Jahren mit dem Blog-Post nichts zu beweisen versucht hat, aber damals sagte er: "Ich hatte es satt, Leute sagen zu hören, Java sei langsam, wenn ich weiß, dass es ziemlich schnell ist ...", was darauf hindeutet Damals gab es etwas, was er zu beweisen versuchte.
Christian Felde sagt: "Ich habe den Code nicht erstellt, sondern nur die Tests wiederholt." Als ob dies ihn von jeder Verantwortung für seine Entscheidung entbunden hätte, Messungen der von Keith Lea ausgewählten Aufgaben und Programme zu veröffentlichen.
Liefern Messungen von nur 25 winzigen Programmen endgültige Beweise?
Diese Messungen gelten für Programme, die im "gemischten Modus" ausgeführt werden. Java wird nicht interpretiert . Sie können leicht herausfinden, wie gut Java "interpretierten Bytecode" ausführt, da Sie Java zwingen können, nur Bytecode zu interpretieren - einfach einige Java-Programme mit und ohne die Option -Xint ausführen.
quelle
Es amüsiert mich, wie allgegenwärtig diese seltsame Vorstellung von "interpretiertem Bytecode" ist. Haben Sie schon einmal von der JIT-Zusammenstellung gehört? Ihr Argument kann nicht auf Java angewendet werden.
Wenn man JVM beiseite lässt, gibt es Fälle, in denen ein direkter Thread-Code oder sogar eine triviale Bytecode-Interpretation einen stark optimierten nativen Code leicht übertreffen können. Die Erklärung ist recht einfach: Bytecode kann recht kompakt sein und passt in Ihren kleinen Cache, wenn eine native Codeversion desselben Algorithmus mehrere Cache-Fehler für eine einzelne Iteration aufweist.
quelle
Abgesehen von JIT, GC usw. kann C ++ sehr, sehr leicht langsamer gemacht werden als Java. Dies wird in Benchmarks nicht angezeigt, aber dieselbe App, die von Java-Entwicklern und C ++ - Entwicklern geschrieben wurde, ist in Java möglicherweise viel schneller.
Was fortgeschrittene Vererbungsmuster betrifft, so sind diese ziemlich ähnlich - C ++ hat einige, die Java nicht hat, und umgekehrt, aber alle von ihnen verursachen auch einen ähnlichen, signifikanten Overhead. Also kein besonderer C ++ Vorteil bei objektlastiger Programmierung.
Eine weitere Einschränkung: GC kann schneller oder langsamer sein als das manuelle Verwalten von Zuweisungen. Wenn Sie viele kleine Objekte zuweisen, wird in der GC-Umgebung normalerweise ein Teil des Arbeitsspeichers zugewiesen und Teile davon werden bei Bedarf für neue Objekte verteilt. In verwaltet - jedes Objekt = separate Zuordnung benötigt erhebliche Zeit. OTOH, wenn Sie viel Speicher auf einmal malloc () und dann Teile davon manuell Ihren Objekten zuweisen oder nur wenige größere Instanzen von Objekten verwenden, können Sie viel schneller auftauchen.
quelle
obj.fetchFromDatabase("key")
drei Mal innerhalb von fünf Codezeilen für denselben Schlüssel schreiben , werden Sie zweimal überlegen, ob Sie diesen Wert einmal abrufen und in einer lokalen Variablen zwischenspeichern möchten. Wenn Sieobj->"key"
mit->
Überlastung schreiben , um als Datenbankabruf zu fungieren, sind Sie viel anfälliger dafür, sie einfach passieren zu lassen, da die Kosten des Vorgangs nicht offensichtlich sind.Irgendwie nimmt Stack Exchange meine anderen Stackpoints nicht an, also ... leider keine Antwort ...
Die am zweithäufigsten gewählte Antwort hier ist meiner bescheidenen Meinung nach jedoch voller Fehlinformationen.
Eine handgerollte App von einem Experten für C / C ++ ist IMMER viel schneller als eine Java-Anwendung. Es gibt kein "so schnell wie Java oder schneller". Es ist nur schneller, gerade wegen der Artikel, die Sie unten zitieren:
JIT-Kompilierung : Erwarten Sie wirklich, dass ein automatischer Optimierer die Intelligenz eines erfahrenen Programmierers besitzt und den Zusammenhang zwischen der Absicht und dem Code erkennt, den die CPU wirklich ausführen wird? Darüber hinaus ist alles, was Sie tun, Zeitverlust im Vergleich zu einem bereits kompilierten Programm.
Garbage Collection ist ein Tool, mit dem Ressourcen, deren Zuordnung ein Programmierer vergessen hätte, mehr oder weniger effizient freigegeben werden.
Offensichtlich kann dies nur langsamer sein als das, was ein Experte (Sie haben den Begriff gewählt) C-Programmierer tun würde, um mit seinem Speicher umzugehen (und nein, es gibt keine Lecks in korrekt geschriebenen Apps).
Eine leistungsoptimierte C-Anwendung kennt die CPU, auf der sie ausgeführt wird, sie wurde kompiliert. Das heißt, Sie haben nicht alle Schritte für die Leistung unternommen, oder?
Laufzeitstatistik Ich bin mir nicht sicher, aber ich vermute, dass ein Experte in C über mehr als genug Branchenvorhersagewissen verfügt, um die automatisierte Optimierung erneut zu überlisten.
Sehr gute Bibliotheken Es gibt viele nicht sehr optimierte Funktionen, die über Bibliotheken in Java verfügbar sind, und das Gleiche gilt für jede Sprache. Die am besten optimierten Bibliotheken sind jedoch in C geschrieben, insbesondere für Berechnungen.
Die JVM ist eine Abstraktionsebene, die sowohl Vorteile impliziert, von denen viele übergeordnet sind, als auch impliziert, dass die Gesamtlösung vom Design her langsamer ist.
Insgesamt:
Java kann niemals die Geschwindigkeit von C / C ++ erreichen, da es in einer JVM mit vielen Schutzfunktionen, Funktionen und Tools funktioniert.
C ++ hat einen klaren Vorsprung bei optimierter Software, sei es für Computer oder Spiele, und es ist üblich zu sehen, dass C ++ - Implementierungen Codierungswettbewerbe gewinnen, bis zu dem Punkt, dass die besten Java-Implementierungen nur auf der zweiten Seite zu sehen sind.
In der Praxis ist C ++ kein Spielzeug und lässt Sie nicht mit vielen Fehlern davonkommen, mit denen die meisten modernen Sprachen fertig werden können. Durch seine Einfachheit und Sicherheit ist es jedoch von Natur aus schneller.
Und als Fazit möchte ich sagen, dass die meisten Leute nicht zwei Cent dafür ausgeben, dass Optimierung letztendlich ein Sport ist, der nur wenigen glücklichen Entwicklern vorbehalten ist und das, außer in Fällen, in denen es wirklich um Leistung geht (Wenn Sie die Hardware mit 10 multiplizieren, hilft dies nichts - oder es sind mindestens ein paar Millionen), bevorzugen die meisten Manager eine nicht optimierte App und eine Tonne Hardware.
quelle
new
odermalloc()
. Es kann im Allgemeinen viel schneller sein als jede manuelle Speicherverwaltung, da Sie Objekte nicht manuell verschieben können. Alle Ihre Überlegungen sind also eindeutig falsch und voreingenommen. Ihre Kenntnisse über GC-Algorithmen und JIT-Optimierungsmethoden sind zu begrenzt.Ich habe mindestens zwei beeindruckende MMOs in Java gesehen, zu sagen, dass es für Spiele nicht schnell genug ist, ist eine falsche Bezeichnung. Nur weil Spieleentwickler C ++ gegenüber anderen Sprachen bevorzugen, heißt das, dass es nicht nur mit Java zusammenhängt, sondern dass Programmierer sich noch nie wirklich mit anderen Programmiersprachen / -paradigmen beschäftigt haben. Jede Sprache, die so fortgeschritten ist wie C / C ++ oder sogar Java, kann Code erzeugen, der das Argument Geschwindigkeit technisch erfüllen oder zunichte machen kann. Das alles hängt davon ab, was Programmierer wissen, mit welchen Teams sie am meisten arbeiten und vor allem, warum sie diese Tools verwenden. Da wir uns mit dem Spielentwicklungsaspekt der Programmierung befassen, muss das Argument mehr beinhalten. Einfach gesagt ' Es dreht sich alles um Geld und Zeit für ein Unternehmen, das darauf aus ist, Tools zu verwenden, die der Qualitätssicherung entsprechen, und in der Praxis spielt es keine Rolle, warum xx Gründe für die Wahl von C ++ gegenüber Java oder einer anderen Sprache ausschlaggebend sind. Es ist nur eine Massenproduktionsentscheidung. Auf der grundlegendsten Ebene der Rechenalgorithmen spielen wir nur mit Einsen und Nullen. Das Geschwindigkeitsargument ist eines der dümmsten Argumente, die jemals auf Spiele angewendet wurden. Wenn Sie Geschwindigkeitszuwächse wünschen, lassen Sie die Programmiersprachen ganz fallen und arbeiten Sie mit Assemblern, die bei weitem der beste Vorteil sind.
quelle