Performace-Test: Java vs. C#



  • Hallo Softwareentwickler,

    zuallererst hoffe ich im richtigen Thread mit meinem Anliegen zu sein.

    OK, ich bin Softwareentwickler und liebe C# (auch C/C++, aber eigentlich nicht Java). Deshalb auch die Auswahl dieses Forums, für mein zum Teil "ketzerisches" Thema. Denn es geht mal wieder um Java vs. C#/.NET!

    Ich hatte den Auftrag bekommen, eine kleine Performance-Untersuchung zwischen Java und C# zu machen. Da ich ein kleines Tool bereits unter C# .NET2.0 programmiert hatte, portierte ich es (im gleichen Programmierstiel) nach Java (RCP/Eclipse) und SWT.

    Das Tool parst die C-Platte rekursiv durch, auf der Suche nach 3 vorher spezifizierten Dateien, und vergleicht die MD5-Checksumme, File-Version, und Erstellungsdatum der Dateien mit Referenzdaten. Die Suche läuft in einem eigenen Thread. In einer Listbox werden die Suchergebnisse, sowie in der obersten Zeile immer das aktuell zu durchsuchende Verzeichnis angezeigt. Die Zeitmessung wurde immer zwischen Start und Ende der Suche gemacht.

    Bei meinem ersten Lauf war C# klar um ca. 50% schneller als Java (Mein PC: PC1). Das bestätigte mich in meinem bisherigen Gefühl.

    Anschließend ließ ich den Java-Code von einem Java-Entwickler durchsehen, der keine großen Änderungen vorgenommen hatte, jedoch war diesmal Java um 50% schneller als C# (PC4).

    Ich untersuchte jetzt auch andere PC's!

    Als Ergebnis erhielt ich folgende Tabelle (Performance von IO-Operationen vor und nach Caching des Filessystems):

    PC              1        2        3         4
    Datenmenge [GB] 27,7	36,2     86,3      48
    Einheit         [s]     [s]      [s]       [s]
    
    .NET First Run  [b]105,80[/b]	[b]223,00[/b]   [b]658,80[/b]    ----
    JAVA First Run  133,50	348,00   779,07    ----
    
    .NET Cached     [b]4,70[/b]     [b]7,80[/b]     229,95     65,00 - 85,00
    JAVA Cached     6,90     11,06    [b]55,58[/b]      [b]35,00 - 38,00[/b]
    ---------------------------------
    PC1+2: Intel Core 2 CPU 6600 @ 2.40GHz, 3,25GB RAM (MEIN PC)
    PC3  : Pentium 4; 3,60 GHz; 2 GB RAM
    PC4  : Pentium M; 2,13 GHz; 2 GB RAM
    

    Diese Tabelle zeigt, dass .NET einen Dual-Core-PC besser unterstützt als Java/Eclipse/SWT. Aber Java auf einen Single-Core (PC3) nach dem Caching um Faktor 4 besser ist als C#.
    Nachdem ich mich vom Schrecken erholt hatte - denn bis zu diesem Zeitpunkt unterstützte ich die Aussage, C# sei um längen besser als Java - machte ich noch einen Test auf PC3 indem ich die Applikationen minimiert laufen ließ. Das Ergebnis überraschte mich wiederum:

    Gleicher Test(PC3; App. miminiert; Zeit in Sekunden;)

    .NET Cached     50,97
    JAVA Cached     43,11
    

    Meine Schlussfolgerung: Irgendetwas an der GUI muss bei C# lahm sein. Sonst kann ich mir diese Zeitverbesserung (Java: 12,47 Sek.; C#: 178,98 Sek.) nicht erklären.

    Nach langem Vortext, jetzt zu meinen Fragen:

    • Ist wirklich .NET's Flaschenhals die GUI?
    • Wie kann es sein, dass unter C# die GUI-Implementierung dermaßen langsam im Vergleich zu SWT ist?
    • Man sollte doch meinen, Microsoft hätte die eigenen Betriebssystem-Mittel optimal im Griff, oder?
    • Wie kann es solche Performace-Unterschiede zwischen Single- und Dual-Core PC's geben?

    Der Vollständigkeit halben noch die Entwicklungsumgebungen:

    - Visual Studio 2005 (.NET 2.0)
    - Eclipse 3.4 (JRE V1.6....)

    Also, auf eine objektive Diskussion bezüglich diesem Thema
    Schang



  • schang schrieb:

    Meine Schlussfolgerung: Irgendetwas an der GUI muss bei C# lahm sein. Sonst kann ich mir diese Zeitverbesserung (Java: 12,47 Sek.; C#: 178,98 Sek.) nicht erklären.

    dann mach den test doch mal ohne gui, z.b. die ergebnisse in eine datei schreiben oder sowas.

    schang schrieb:

    Nach langem Vortext, jetzt zu meinen Fragen:
    Wie kann es solche Performace-Unterschiede zwischen Single- und Dual-Core PC's geben?

    wenn ich mich recht entsinne, läuft 'ne java-vm per default nur auf einem kern. wahrscheinlich macht .NET das besser und parallelisiert selbständig irgendwas.
    🙂



  • wie ist es wenn du keine GUI implementierst sondern es nur ein plain text files schreiben laesst ?



  • Mr Evil schrieb:

    GreaseMonkey: Hide unregistered users; Status: Run

    ^^hehe, schön doof. lieber wiederholen, was schon einer geschrieben hat, ne?
    🙂



  • Ohne das jetzt beleidigend zu meinen: Hast Du auch in Betracht gezogen das Deine C# Performanceprobleme an Dir bzw. Deinem Wissenstand liegen könnten?

    Es gab zu dem Thema Performanceunterschiede von Sprachen schon viele Studien und eines der Ergebnisse war, daß der Skill des Entwicklers einen viel größeren Einfluß auf die Performance hat als die Sprachunetrschiede.

    Oder einfach gesagt, ein sehr guter C# Programmierer holt mehr Performance heraus als ein schlechter Java Progger und umgekehrt.

    Gerade C# und Net Framework hat viele versteckte Performance-Fallen.

    Billiges Beispiel: (Sollte eigendlich jeder hier kennen)

    string tmp = "1";
    tmp += "2";
    tmp += "3";
    tmp += "4";
    tmp += "5";
    tmp += "6";
    
    StringBuilder temp;
    temp.Append("1");
    temp.Append("2");
    temp.Append("3");
    temp.Append("4");
    temp.Append("5");
    temp.Append("6");
    
    string ergebnis = temp.ToString();
    

    Welche der beiden Varianten ist die performantere, warum und um welchen Faktor?



  • Hi loks,

    loks schrieb:

    Ohne das jetzt beleidigend zu meinen: Hast Du auch in Betracht gezogen das Deine C# Performanceprobleme an Dir bzw. Deinem Wissenstand liegen könnten?

    Beleidigt fühl ich mich nicht, denn es ist häufig ein Problem, dass in einem Performance check, die eine (favorisierte) Seite laufzeittechnisch "optimiert" wird, die andere aber nicht (ähnlich deinem Beispiel).
    Ich schrieb deswegen oben extra:

    ...portierte ich es (im gleichen Programmierstiel)...

    Was so viel heißt: Kein StringBuilder in C# und auch keinen für Java.

    Ich habe mir wirklich Mühe gegeben, die Vorgehensweise bei beiden gleich zu lassen.

    @~fricky & Mr Evil
    Ich werde es demnächst Testen, und die Ergebnisse eintragen.

    Vielen Dank jetzt schon mal für eure Beiträge

    Schang



  • schang schrieb:

    Ich habe mir wirklich Mühe gegeben, die Vorgehensweise bei beiden gleich zu lassen.

    Gerade das könnte aber ein Problem sein. Was wenn die Vorgehensweise rein zufällig in Java "Best Practice" ist und in C# "Worst Practice", es aber für C# einen alternativen Implementierungsweg gibt den man eigendlich benutzen sollte der viel schneller ist?



  • zu beachten ist auch das die darstellung der GUI zwischen Forms und WPF nicht gleich zu setzen ist - auch dort gibts performanceunterschiede



  • @lok:
    ich bin in erster Linie C#-Entwickler. Deshalb würde ich für den am Anfang beschriebenen Fall dieses genau umdrehen, also: "Best Practise" für C# und "Worst Practise" für Java/SWT.

    @Mr Evil

    zu beachten ist auch das die darstellung der GUI zwischen Forms und WPF nicht gleich zu setzen ist - auch dort gibts performanceunterschiede

    ich habe WinForms für die Test-Anwendung verwendet. WPF kenn ich leider nicht. Wie sieht es denn dort mit Performance-Unterschiede zwischen WinForms und WPF aus? Welche Bibiliothek ist schneller?

    @ALLE
    Ich habe jetzt den Test nochmals auf Konsole portiert, diesmal ohne Thread für das rekursive Parsen des Dateisystems.

    Die Ergebnisse sind folgende:

    PC              1          2          3        
    Datenmenge [GB] 27,7      36,2       86,3      
    Einheit         [s]       [s]        [s]       
    
    .NET First Run   [b]98,27[/b]    [b]202,70[/b]    [b]548,80[/b]  
    JAVA First Run  137,96    369,40    596,89  
    
    .NET Cached     [b]4,10[/b]       [b]6,58[/b]      [b]25,14[/b]   
    JAVA Cached     6,66      10,64      33,48    
    
    ---------------------------------
    PC1+2: Intel Core 2 CPU 6600 @ 2.40GHz, 3,25GB RAM (MEIN PC)
    PC3  : Pentium 4; 3,60 GHz; 2 GB RAM
    

    Dass C# jetzt durchweg das Rennen gewinnt ist auf jeden Fall ein Indiez für eine schlechte GUI-Bibliothek, oder?

    Was meint Ihr, woran die schlechte GUI-Performance festzumachen ist?

    Gruß
    Schang



  • Ohne die dazu passenden Sources wird Dir da keiner eine Antwort geben können.



  • es kommt auf die hardware an ob WPF schneller ist - da WPF den inhalt rendert und wenns die grafikkarte her gibt es diese machen laesst (wenns nicht sogar ohne pruefung an die graka delegiert wird, muesste ich nochmal nachlesen)
    ich selber hab nur kurz mit forms rum gemacht und bin gleich zu WPF ueber



  • schang schrieb:

    @lok:
    ich bin in erster Linie C#-Entwickler. Deshalb würde ich für den am Anfang beschriebenen Fall dieses genau umdrehen, also: "Best Practise" für C# und "Worst Practise" für Java/SWT.

    Best Practice bedeutet nicht immer max Performance.

    Z.B. wird folgendes durchgehend als Best Practice vorgestellt:

    String ausgabe = String.Format("{0} {1}", "Hallo", "Welt");
    

    Dies ist aber gleichzeitig auch die langsamste der möglichen Lösungen. Warum man es trotzdem als Best Practice nehmen sollte liegt darin, das reine Performance nicht immer oberstes Gebot ist.

    z.B. die schnellste Lösung ist immer noch

    String ausgabe = "Hallo" + "Welt";
    

    Oder z.B. sollte man in C# alle methoden einer Klasse die nicht auf Klassenvariablen zugreifen aus Performancegründen als static markieren weil dadurch bestimmte Prüfungen zu Laufzeit wegfallen.

    Erschwerend kommt hinzu das der JIT Compiler den Code ja erst auf der Zielmachine Compiliert/Optimiert und das auch von Laufzeitvariablen wie freiem Speicher etc abhängig machen kann. Das gleiche C# Programm kann also durchaus zu unterschiedlichem Binärcode mit unterschiedlichen Optimierungen führen je nach Rechner.

    Wie andere schon sagten, ohne konkreten Code kann man hier nicht mehr viel mehr zu sagen.



  • z.B. die schnellste Lösung ist immer noch

    C# Code:
    String ausgabe = "Hallo" + "Welt";

    string ausgabe = "Hallo Welt";
    


  • Knuddlbaer schrieb:

    z.B. die schnellste Lösung ist immer noch

    C# Code:
    String ausgabe = "Hallo" + "Welt";

    string ausgabe = "Hallo Welt";
    

    Ist (in diesem Fall) identisch. Der Compiler verschmilzt Konstanten.



  • nicht ganz das selbe #gg

    String ausgabe1 = "Hallo" + "Welt";
    string ausgabe2 = "Hallo Welt";
    
    ausgabe1 == "HalloWelt";
    ausgabe2 == "Hallo Welt";
    


  • Ist das nicht eher ein reiner I/O-Performance Test? Bei deinem Test vergleichst du praktisch nur die Geschwindigkeit und den Zugriff auf die darunter liegende Festplatte und eine Menge Stack-Operationen.

    Ich bezweifle auch, dass die GUI bei deiner Funktion ein Flaschenhals ist. Um das heraus zu finden, vergleiche mal die Aktivität beider GUIs.

    Um die wirkliche Performance zu testen, würde ich mehr Wert auf Garbage Collector (Dynamischer Speicher), große String-Operationen, Collections etc. verpackt in Multi-Threading legen. Das kommt doch einer realen Software wesentlich näher.

    Gruß Vanish



  • Hallo Vanish

    Zuerst einmal existierte die Anwendung bereits, bestehend aus einem WorkerThread, der die Platte durchsucht und Ergebnisse in der GUI anzeigt. Ich habe diese "kleine" Software ausgewählt, um eine normale "Anwendung" zu testen, die ein paar Controls hat. Zugegeben, dieser Test ist sehr I/O-lastig. Doch das wußte ich vor dem Test bereits.

    Die einzige GUI-Aktion, die in der Software während der Messung ständig passiert, ist das Schreiben des aktuellen Suchpfades in einer Listbox an oberster Position (Index==0), sowie das Anhängen der Ergebnisse darunter.

    Meiner Meinung nach war dies eher ein Test/Vergleich über die Stärke des Frameworks, d.h. die Frage war: "Wie performant ist das .NET-Framework im Vergleich zu Java". Ich war selber überascht, dass es ausgerechnet an der GUI lag, dass meine Applikation so schlecht abschnitt. Wenn man beide Testläufe vergleicht (mit und ohne GUI) kann man dies wahrscheinlich schon rauslesen. Ohne GUI ist klar C# vorne. Mit GUI hat Java/SWT zumindest bei Single-Core die Nase vorn.

    VanishOxiAction schrieb:

    Um die wirkliche Performance zu testen, würde ich mehr Wert auf Garbage Collector (Dynamischer Speicher), große String-Operationen, Collections etc. verpackt in Multi-Threading legen. Das kommt doch einer realen Software wesentlich näher.

    Klar, wenn ich die GUI abschalte, reduziert sich die Prüfung auf die von Dir benannten Dinge. Und das zeigt auch mein zweiter Test. Ohne GUI ist C#.NET klar schneller.

    Bei einem weiteren Test, der alle Dateien als FileInfo in eine Generic-List ablegt, und anschließend durchsucht, ist C# beim durchlaufen der List um Faktor >10 schneller als Java!!!

    Wenn jetzt mein Test nichts über die Performance der GUI aussagt, welche Tests müsste man machen, damit man die GUI-Performance bestimmen kann?

    Ich weiß, dass die SWT Bibliothek nativ kompiliert ist und WinForms nicht. Liegt es vielleicht daran?

    Gruß
    schang



  • Hast Du es mal mir Profiling versucht um einfach zu schauen welcher Teil die meiste Rechenzeit verbraucht?



  • Knuddlbaer schrieb:

    Ohne die dazu passenden Sources wird Dir da keiner eine Antwort geben können.



  • Die .NET GUI ist furchtbar lahm, das überrascht mich garnicht.

    @VanishOxiAction:

    Um die wirkliche Performance zu testen, würde ich mehr Wert auf Garbage Collector (Dynamischer Speicher), große String-Operationen, Collections etc. verpackt in Multi-Threading legen. Das kommt doch einer realen Software wesentlich näher.

    Äh. Bei Server-Anwendungen und Commandline-Tools vielleicht. Bei typsichen GUI Applikationen die kaum was rechnen aber viele bunte Fenster haben ist es ganz sicher nicht so, da überwiegt der Teil der im GUI Framework draufgeht bei weitem.


Anmelden zum Antworten