Seite 1 von 2

Generics und Java

Verfasst: 01.06.2012, 13:49
von spobat
Doch kurz was zu den Generics:
Was glaubt ihr, welche Generics sind performanter: Die von Java oder die von C#?

Ich kann mir vorstellen, dass es schon ein bisschen dauert, bis in C# die Generics "generiert" wurden, ich glaube aber, dass wenn die Klassen dann intensiv genutzt werden sich das auszahlt.
Bei Java verliert man die meiste Performance durch das casten, oder?
Das heisst, bei einer generischen Klasse mit einer generischen methode die ich nur einmal aufrufe, bin ich bei Java vermutlich guenstiger dran; call' ich die methode 1000 mal vermutlich in c#.
Liege ich da richtig mit der Denkweise?

@cat
Gratulation zum 1000. Beitrag *g*

Anmerkung: Abgetrennt von RAII und Java.

Re: RAII und Java

Verfasst: 01.06.2012, 13:56
von dot
dst hat geschrieben:Doch kurz was zu den Generics:
Was glaubt ihr, welche Generics sind performanter: Die von Java oder die von C#?
C# natürlich. Java "Generics" sind ja auch wieder kaum mehr als Syntaxzucker. I sense a pattern...
dst hat geschrieben:Bei Java verliert man die meiste Performance durch das casten, oder?
Vermutlich am meisten durch die unnötige Indirektion, die das Ganze in allen möglichen Dimensionen ineffizient macht...

Re: RAII und Java

Verfasst: 01.06.2012, 15:03
von spobat
@dot
Was meinst du mit "Indirektion"?

Re: RAII und Java

Verfasst: 01.06.2012, 15:23
von dot
dst hat geschrieben:@dot
Was meinst du mit "Indirektion"?
Naja, nehmen wie eine List<int>. Da C# echte Generics hat, wird das im Prinzip zu einem einfachen int Array und fertig.
In Java dagegen kann ich das erstmal schon gar nicht einfach so hinschreiben, da Java weder richtiges Boxing noch ein Konzept von Typen mit Wertsemantik hat (letzteres wäre natürlich eine Voraussetzung für richtige Generics). Mittlerweile gibt es afaik etwas zusätzlichen Syntaxzucker, der den Umgang damit erleichtert (sie nennen das "Autoboxing", natürlich nicht zu verwechseln mit richtigem Boxing). Man beachte: In alter Java Tradition werden natürlich auch all diese Probleme einfach an den Stellen wo sie an die Oberfläche treten mit mehr und mehr Syntaxzucker bedeckt, anstatt sie zu lösen. Diese List<Integer> speichert nun natürlich kein Array aus int, sondern ein Array aus Verweisen auf Objekte, die jeweils einen int enthalten (da versteckt sich die zusätzliche Indirektion). Im Falle von int, verbraucht das Ding also schonmal rein prinzipiell doppelt soviel Speicher als notwendig. Dazu kommt, dass diese Integer Objekte nun alle einzeln allokiert werden, statt in einem gemeinsamen Block. Das ist nicht nur langsam, sondern hilft auch schön dabei, den Heap zu fragmentieren. Die richtige Performancebremse kommt aber erst: Wenn du diese Liste nun durchlaufen willst, kannst du nicht einfach einen linearen Speicherbereich durchgehen, sondern musst für jeden Integer erst mal den Verweis aus dem Array lesen und dann dort im Speicher nachschauen, wo der eigentliche Integer liegt. Ganz besonders für moderne CPUs ist das alles andere als optimal. Die C# List<int> dagegen liefert mir praktisch vergleichbare Performance mit einer guten C++ Lösung...

Achja:
dst hat geschrieben:Als laecherlich wuerde ich ihn nicht bezeichnen, da er von Oracle kommt, worauf man normal einiges halten kann.
Meine Meinung von Oracle willst du lieber nicht hören. Wenn man sich mal anschaut was diese Firma so alles treibt, dann will man eigentlich am besten nichts mit denen zu tun haben. Die Tatsache dass ein respektabler Konzern wie Sun von so einem niederen Patenttroll gefressen wurde, stimmt mich traurig, obwohl ich von Java nie viel gehalten hab...

Re: RAII und Java

Verfasst: 01.06.2012, 15:47
von spobat
@dot
Mensch dot. Das ist mal wieder nur die halbe Wahrheit. :)
List<T> ist in Java ein Interface. Du kannst dir keine dermassigen Behauptungen ueber Implementierungen, hier ueber Java, erlauben.
In Java gibts z.b. ne ArrayList und ne LinkedList. Ne LinkedList macht genau das was du sagst, mit allen "Nachteilen".
Ne ArrayList verhaelt sich dagegen genau wie die von dir in c# beschriebene List<T>. Ich denke mal, dass C# auch ne LinkedList<T> hat, aber List<T> als ArrayList<T> interpretiert wird.
Was man gelten lassen koennte, ist dass es in Java keine primitive-type-generics gibt.

Ich meine aber mit dem bezug auf generics weniger die implementierungsdetails als die theoretische Umsetzung die ja wie folgt aussieht:
Java: Alles sind Object's zur runtime, und wird auch dementsprechend gecastet. Wirkliche generische Klassen werden weder zur compile noch zur runtime generiert. Performanceeinbussen entstehen hier vmtl. durch die ganze casterei.
C#: Generische Klassen werden zur runtime generiert, kein casting noetig. Performanceinbussen entstehen vmtl. durch die 1x -ige generierung des Generics beim ansprechen des Klassenkontexts.
Um aus diesen beiden auf die performance zu schliessen.
dot hat geschrieben:Meine Meinung von Oracle willst du lieber nicht hören. Wenn man sich mal anschaut was diese Firma so alles treibt, dann will man eigentlich am besten nichts mit denen zu tun haben.
Sie haben das schnellste / maechtigste DBMS auf dem Markt, soweit mir bekannt ist?
MMnach sollte ja Google Java kaufen, dann habe Sie die ewigen Konflikte mit Oracle bzgl Android auch geloest, und koennen das Gesamte Ding besser vorantreiben. Da Google ne Menge faehiger Leute hat,
kann ich mir vorstellen, dass die aus Java noch mehr machen.

Re: RAII und Java

Verfasst: 01.06.2012, 15:51
von Schrompf
<nutzloser Einwurf entfernt>

Re: RAII und Java

Verfasst: 01.06.2012, 15:54
von dot
dst hat geschrieben:Mensch dot. Das ist mal wieder nur die halbe Wahrheit. :)
List<T> ist in Java ein Interface. Du kannst dir keine dermassigen Behauptungen ueber Implementierungen, hier ueber Java, erlauben.
In Java gibts z.b. ne ArrayList und ne LinkedList.
Richtig, ich meinte natürlich ArrayList. Ersetze in meinem obigen Posting also List durch ArrayList und dann stimmt alles wieder. Zumindest meines Wissens nach. Wenn ich falsch liege, dann lass ich mich gern eines Besseren belehren.
dst hat geschrieben:Ich meine aber mit dem bezug auf generics weniger die implementierungsdetails als die theoretische Umsetzung die ja wie folgt aussieht:
Java: Alles sind Object's zur runtime, und wird auch dementsprechend gecastet. Wirkliche generische Klassen werden weder zur compile noch zur runtime generiert. Performanceeinbussen entstehen hier vmtl. durch die ganze casterei.
Die Performanceverhältnisse sind genau eine Folge der oben dargelegten Implementierungsdetails. Eine ArrayList aus Referenztypen ist in Java und C# natürlich wohl in etwa gleich schnell.

Re: RAII und Java

Verfasst: 01.06.2012, 16:02
von Alexander Kornrumpf
Syntaxzucker
Das ironische ist ja dass genau dieses Argument, zumindest war es so noch vor einigen Jahren, in der Java Community verwendet wird um gegen Neuerungen an der Sprache zu argumentieren. Aber was sollen sie auch sonst tun? Die fundamentalen Probleme mit der Sprache wird man wohl nicht beheben können ohne Millionen von Zeilen Java Code zu zerstören.

Nichtsdestoweniger muss es ja einen Grund haben warum sich Java an Unis und in der Wirtschaft durrchgesetzt hat. Opinions?

Re: RAII und Java

Verfasst: 01.06.2012, 16:04
von dot
Alexander Kornrumpf hat geschrieben:Nichtsdestoweniger muss es ja einen Grund haben warum sich Java an Unis und in der Wirtschaft durrchgesetzt hat. Opinions?
Wirtschaft: Selber Grund wie z.B. auch bei PHP: Weil jeder damit sehr schnell was irgendwie funktionierendes zusammenhacken kann. Unis: Mir fällt kein vernünftiger Grund ein, außer dass es eben in der Wirtschaft starke Verbreitung genießt. Häng aber wohl auch stark davon ab was und wo man studiert. Mein Studium z.B. ist (gottseidank) sehr stark C++ betont...

Abgesehen davon erwarte ich, dass Java in Zukunft auf längere Sicht an Bedeutung verlieren wird, zumindest was neue Software angeht, außer vielleicht bei Serveranwendungen. Ein weiterer Grund wieso ich jedem Java Programmierer nur raten kann, sich mit C++ auseinanderzusetzen ;)

Re: RAII und Java

Verfasst: 01.06.2012, 16:32
von spobat
Auf Anfrage ein kleiner Vergleich C# - Java.
// langsam wirds offtopic :mrgreen: :mrgreen:

Getestet habe ich eine ArrayList mit einer Millionen int eintraegen. Diese wird erst befuellt, dann werden die int's einzeln ausgelesen.
Interessant waeren zur bestaetigung natuerlich noch andere Collections mit anderen Typen, da das arbeiten mit ints in jeder sprache trivial ist.

Code: Alles auswählen

public class Main {
	public static void main(String[] args) throws IOException {
		final int NUM_ITEMS = 1000000;
		
		List<Integer> list = new ArrayList<>(NUM_ITEMS);

		{
                        // Version 2
			//Integer[] intArray = new Integer[NUM_ITEMS];
			//for (int i = 0; i < NUM_ITEMS; ++i) {
			//	intArray[i] = i;
			//}
			
			// Insert
			long tStart = System.currentTimeMillis();
			for (int i = 0; i < NUM_ITEMS; ++i) {
				list.add(i); // Version 1
				//list.add(intArray[i]); // Version 2
			}
			long tEnd = System.currentTimeMillis();

			System.out.println("Insert dt:" + (tEnd - tStart));
		}
		

		{
			// Read
			long sum = 0;
			long tStart = System.currentTimeMillis();
			for (int i = 0; i < NUM_ITEMS; ++i) {
				sum += list.get(i);
			}
			long tEnd = System.currentTimeMillis();

			System.out.println("Read dt:" + (tEnd - tStart));
			System.out.println("Read sum: " + sum);
		}

	}
}
Durchschnitts Resultat, Version 1:

Code: Alles auswählen

Insert dt:70
Read dt:16
Read sum: 499999500000

Durchschnitts Resultat, Version 2 (Hier wurde das Array vorher befuellt, und dann die Integer instanzen in die Liste eingefuellt; Ein mitmessen des befuellen des Arrays sorgt fuer aehnliche ergebnisse wie in Version 1):

Code: Alles auswählen

Insert dt:16
Read dt:16
Read sum: 499999500000
Was auffaellt ist, dass die ganze herumcasterei extrem viel ausmacht. Worin man das sieht ist klar denke ich.

Nun zur c# version. Ich hoffe eindringlich, dass ich das benchmarking richtig gemacht habe, da ich mit c# normal nicht viel am hut habe. Korrigiert mich bitte.

Code: Alles auswählen

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            const int NUM_ITEMS = 1000000;

            List<int> list = new List<int>(NUM_ITEMS);
            Stopwatch stopwatch = new Stopwatch();

		{
			// Insert
			stopwatch.Start();
            for (int i = 0; i < NUM_ITEMS; ++i)
            {
				list.Add(i);
			}
			stopwatch.Stop();

			Console.WriteLine("Insert dt:" + stopwatch.ElapsedMilliseconds);
		}		
            stopwatch.Reset();
		{
			// Read
			long sum = 0;
			stopwatch.Start();
            for (int i = 0; i < NUM_ITEMS; ++i)
            {
	  		sum += list[i];
	    }
			stopwatch.Stop();

			Console.WriteLine("Read dt:" + stopwatch.ElapsedMilliseconds);
			Console.WriteLine("Read sum: " + sum);
		}            
        }
    }
}
Durchschnittsresultat:

Code: Alles auswählen

Insert dt:14
Read dt:11
Read sum: 499999500000
Trotz "wegschummeln" der Java casts produziert der c# code immer noch bessere ergebnisse!

#Edit: Das Forum hat die einrueckungen leider etwas zerstoert :/
Habe es nochmal auf ideone.com geladen:
Java: http://ideone.com/lXy6D
C#: http://ideone.com/RUbNx

Re: RAII und Java

Verfasst: 01.06.2012, 17:00
von CodingCat
dst hat geschrieben:Was auffaellt ist, dass die ganze herumcasterei extrem viel ausmacht. Worin man das sieht ist klar denke ich.
Du ziehst die falschen Schlüsse. Das, was du hier misst, ist genau das, was dot beschrieben hat. In Java hast du ein Array von Zeigern auf Integer-Objekte. In C# hast du ein Array von ints. Wenn du mal den Speicherbedarf misst, wirst du feststellen, dass die Java-Version mindestens doppelt so viel Speicher verbraucht. Ganz davon abgesehen, dass du beim Durchlaufen des Arrays in Java für jedes Element zusätzlich einen Zeiger dereferenzieren musst, eben genau die zusätzliche Indirektion. In C++-Notation ausgeschrieben passiert in Java folgendes:
int *p = list.get(i); int i = *p; sum += i;
In C# hingegen hast du:
int i = list.get(i); sum += i;

Das ist IMO eine der größten Verfehlungen von Java überhaupt. Bei elementaren Typen kannst du dich retten, indem du nur echte Arrays von eingebauten Typen nutzt, z.B. int[n] oder float[n], NICHT jedoch Integer[n] etc. Aber schon für zusammengesetzte Typen bist du mit Java komplett am Ende. Ein Array von Vektoren kannst du z.B. speichereffizient nur als float x[n]; float y[n]; speichern, nicht jedoch als vec2 v[n]. Das ist wirklich absolut lächerlich und ein Grund dafür, dass ich diese Sprache niemals ernsthaft für datenintensive Projekte in Betracht ziehen würde.

Re: RAII und Java

Verfasst: 01.06.2012, 17:05
von spobat
@cat
Ja, durch die dereferenzierung dauert das Lesen in Java laenger als in C#, da geb ich dir recht.

Dass mein schluss falsch waere, glaube ich dir allerdings nicht.
Der Schluss beruht auf den 2 Versionen der Java version, sieh dir die bitte nochmal an. Im grunde wird bei dem eine das casten mit getimed, bei dem anderen nicht.
Wenn ich die casts erst vornehme, naemlich in das Integer[] array, und dann erst in die Liste einfuege sparte ich 54 ms.
(Natuerlich spare ich nicht wirklich 54ms, da das genau die zeit ist, die es dauert die int's nach Integer zu casten und in das Array einzufuegen. Durch das anlegen des Arrays sinds wohl zusaetzlich noch 2, 3 ms mehr)

Re: RAII und Java

Verfasst: 01.06.2012, 17:08
von CodingCat
dst hat geschrieben:Dass mein schluss falsch waere, glaube ich dir allerdings nicht.
Der Schluss beruht auf den 2 Versionen der Java version.
Wenn ich die casts erst vornehme, naemlich in das Integer[] array, und dann erst in die Liste einfuege sparte ich 54 ms.
(Natuerlich spare ich nicht wirklich 54ms, da das genau die zeit ist, die es dauert die int's nach Integer zu casten und in das Array einzufuegen. Durch das anlegen des Arrays sinds wohl zusaetzlich noch 2, 3 ms mehr)
Nein, das sind keine Casts. Das sind vollständige Objektkonstruktionen, ausgeschrieben list.add(new Integer(i)). Gerade bei der Erzeugung nimmst du also an der zusätzlichen Indirektion großen Schaden.

Re: RAII und Java

Verfasst: 01.06.2012, 17:10
von spobat
@cat
Sieh der den code nochmal an, speziell den auskommentieren, der die Version 2 darstellt. Dann faellt der groschen :).
Fuer die 1. Version hast du da vollkommen recht, yep!

Re: RAII und Java

Verfasst: 01.06.2012, 17:11
von CodingCat
Nein, bei dir müsste langsam mal der Groschen fallen. In Version 2 konstruierst du die Objekte vorher. In Version 1 misst du die Konstruktion mit. Casts misst du in keinem oder beiden Fällen.

Re: RAII und Java

Verfasst: 01.06.2012, 17:13
von spobat
Der Cast von int nach Integer impliziert die erstellung von Integer objekten.

Re: RAII und Java

Verfasst: 01.06.2012, 17:16
von CodingCat
Genau, deshalb ist es auch kein Cast, sondern eine Konstruktion. Casts sind ziemlich sicher wesentlich billiger als Konstruktionen. ;)

Re: RAII und Java

Verfasst: 01.06.2012, 17:17
von Artificial Mind
Cat: Java-Programmierer und auch einige C#-Programmierer nennen alle "Typumwandlungen" (und sei es durch Konstruktion eines anderen Types) Casts.

Re: RAII und Java

Verfasst: 01.06.2012, 17:18
von CodingCat
Schön für sie, der Performance-Bottleneck ist in diesem Fall trotzdem die Konstruktion, und nicht der Cast. :P

Implizit findet in Java nach der Konstruktion ein Cast in Object statt. Genau um diese Casts ging es doch bei dem Vergleich von Java- und C#-Generics. Aber genau diese Casts sind in diesem Fall nicht wirklich entscheidend. ;)

Tatsächlich sollten die Casts bedingt duch das Java Object Layout zu vernachlässigen sein, möglicherweise sogar nops, zumindest die Downcasts Upcasts.

Re: RAII und Java

Verfasst: 01.06.2012, 17:25
von spobat
@cat
Ich meinte natuerlich die Casts der erstellung, die 54 ms ausmachen (sonst waere die lesedauer ja auch erheblich groesser).
Wie gesagt, der Cast impliziert die Konstruktion.
Die casts, die der generics-mechanismus (nach Object) verursacht, scheint tatsaechlich nicht messbar.

Wenns dazu noch mehr zu sagen gibt, sollte man eventuell darueber nachdenken, das abzusplitten, da das nichts mehr viel mit "RAII und Java" zu tun hat. Aber ich denke unser "off topic exkurs" ist hiermit ausgesprochen :)

Re: RAII und Java

Verfasst: 01.06.2012, 17:30
von CodingCat
dst hat geschrieben:Die casts, die der generics-mechanismus (nach Object) verursacht, scheint tatsaechlich nicht messbar.
Ja, wie dot schon sagte, der entscheidende Performanceunterschied kommt durch das Fehlen von Value Types in Java. Man beachte allerdings, dass der Hack mit Casts von und zu Object nur deshalb geht, weil Java gar keine Value Types hat. Mit der Einführung von Value Types wäre es also nicht getan, Java müsste dann gleichzeitig auch Generics ganz neu umsetzen.

Re: RAII und Java

Verfasst: 01.06.2012, 17:32
von spobat
CodingCat hat geschrieben:Ja, wie dot schon sagte, der entscheidende Performanceunterschied kommt durch das Fehlen von Value Types in Java. Man beachte allerdings, dass der Hack mit Casts von und zu Object nur deshalb geht, weil Java gar keine Value Types hat. Mit der Einführung von Value Types wäre es also nicht getan, Java müsste dann gleichzeitig auch Generics ganz neu umsetzen.
Java hat value types. Aber nicht fuer generics. Yep, gehoert neu umgesetzt^^. Bin ich auch klar dafuer. :)

Re: RAII und Java

Verfasst: 01.06.2012, 17:32
von CodingCat
dst hat geschrieben:@cat
Java hat value types. Aber nicht fuer generics. Yep, gehoert neu umgesetzt^^. Bin ich auch klar dafuer. :)
Seit wann das?

Re: RAII und Java

Verfasst: 01.06.2012, 17:33
von spobat
CodingCat hat geschrieben:
dst hat geschrieben:@cat
Java hat value types. Aber nicht fuer generics. Yep, gehoert neu umgesetzt^^. Bin ich auch klar dafuer. :)
Seit wann das?
Schon immer. http://docs.oracle.com/javase/tutorial/ ... types.html

..oder redest du fuer eine einfuehrung des "struct" keywords (bzw. aehnlicher mechanismus)? Glaube ich aber nicht..

Re: RAII und Java

Verfasst: 01.06.2012, 17:34
von CodingCat
Sehr witzig. Ich rede offensichtlich nicht von primitiven Typen, wie toll man mit denen arbeiten kann, habe ich doch gerade eben schon elaboriert.

Re: RAII und Java

Verfasst: 01.06.2012, 17:37
von CodingCat
dst hat geschrieben:..oder redest du fuer eine einfuehrung des "struct" keywords (bzw. aehnlicher mechanismus)? Glaube ich aber nicht..
Mir egal welches Keyword. Aber klar, wovon denn sonst. Genau darum geht es doch die ganze Zeit.

Re: RAII und Java

Verfasst: 01.06.2012, 17:38
von spobat
Es geht ja nicht darum, ob Java ValueTypes wie C# (siehe struct) hat oder nicht, sondern darum, dass die Java Generics nicht generisch sind, sondern an Klassen gebunden sind.
Wenn die Generics fuer die primitiven Typen funktionieren wuerden, waere das doch voellig ausreichend. Was willst du dafuer dann noch ValueTypes? Das ist imo ein 3. Thread, der sich aus diesem abspalten koennte.^^

Re: RAII und Java

Verfasst: 01.06.2012, 17:43
von CodingCat
dst hat geschrieben:Es geht ja nicht darum, ob Java ValueTypes wie C# (siehe struct) hat oder nicht, sondern darum, dass die Java Generics nicht generisch sind, sondern an Klassen gebunden sind.
Wenn die Generics fuer die primitiven Typen funktionieren wuerden, waere das doch voellig ausreichend. Was willst du dafuer dann noch ValueTypes? Das ist imo ein 3. Thread, der sich aus diesem abspalten koennte.^^
Mir fallen spontan unzählige Value Types ein. Darunter fallen mathematische Objekte und eigentlich jede Art von Datensatz, die man kompakt in großer Zahl speichern will. Natürlich ist es ärgerlich, dass man wohl größere Datensätze immer gleich in Value und in Reference Version bräuchte, Value für kompakte Speicherung, Reference für Rumreichen ohne ständiges Kopieren. (Wobei C# soweit ich weiß eine Möglichkeit zum Rumreichen von Referenzen auf Value Types bietet.)

Re: RAII und Java

Verfasst: 01.06.2012, 17:50
von CodingCat
Alexander Kornrumpf hat geschrieben:Nichtsdestoweniger muss es ja einen Grund haben warum sich Java an Unis und in der Wirtschaft durrchgesetzt hat. Opinions?
Meine bisherigen Erfahrungen geben mir eine sehr ernüchternde Antwort. Und die wäre in beiden Fällen, weil kaum jemand wirklich Ahnung hat. Obendrein ist die Sachlage ziemlich frustrierend. C++ leidet unter der Altlast von C bisweilen bis zur Impraktikabilität in Sachen Modulsystem und Grammatik. Java leidet unter großen Verfehlungen im Sprachentwurf. C# leidet unter seiner starken Verflechtung mit .NET. Java und C# leiden unter ihrem "Managed"-Entwurf. Meine Traumsprache ist mit Sicherheit noch nicht dabei.

Re: Generics und Java

Verfasst: 01.06.2012, 18:04
von spobat
Ein guter grund, warum Java so "schlecht" im vergleich mit c# abschneidet ist, dass c# erst 6 Jahre spaeter entstanden ist.
Die konnten sich so natuerlich perfekt abgucken, was laeuft und was laeuft nicht. Java war mit dem garbage collection system und einigen andren Konzepten ein Vorreiter und hat damit eine regelrechte Welle ausgeloest.
Jetzt ist das natuerlich vielfach ueberholt, und es laesst sich nicht abschaffen, dank der backward compatibility.

C# hat sich imo aus 2 gruenden nicht durchgesetzt:
MS ist geldgeil und will alleine "herrschen", deshalb bringen sie keine VM's fuer andre OS'e raus. Es gibt unzaehlige viele Dummheiten, die MS nur des Geldes wegen macht. Seit neustem
nennt man das auch "aus Marketing gruenden".
Das andre ist, dass es nach Java erschienen ist, und wer zu erst kommt, der mahlt zu erst. Aber die letzten werden die ersten sein.


..und wenn so eine Sprache ueber lange Zeit wirklich bestehen soll dann wirds halt so wie bei Python...