Zum Inhalt springen

wieso läuft es (angeblich) langsamer???


pecunia

Empfohlene Beiträge

Hallo!

Wieso

int array = new int[1000];

for(int x=0; x<100; x++)

for(int y=0; y<100; y++)

array[x+y*90] = 1;

soll wesentlich langsamer laufen als:

int array = new int[1000];

for(int y=0; y<100; y++)

for(int x=0; x<100; x++)

array[x+y*90] = 1;

Angeblich aus mehreren Gründen, die ich leider nicht verstehe...; hauptsächlich jedoch wegen Speicherzugriff...

Gruß

pecunia

Link zu diesem Kommentar
Auf anderen Seiten teilen

Der Effekt ist dieser: Der Computer ist gebaut für sequenziellen Speicherzugriff. Es wirden immer 32 oder 64 byte große Blöcke (Cache Lines) aus dem langsamen Hauptspeicher in den Cache geladen. Wenn du natürlich immer nur ein byte/int/... aus jeden Block brauchst, muß oft auf den Hauptspeicher zugegriffen werden. Daher geht die Performance beim ersten Beispiel merklich runter. Ob das bei Java auch (verglichen zu C++ etc) so ist, ist eine andere Frage. Vom Sourcecode weg bis zu den ausgeführten Action passiert viel mit dem Code. Das können nur Leute sagen, die die Interna des Java Compilers und der VM gut kennen. Vermutlich wird der Code so optimiert, daß er optimal läuft., d.h die Schleife gegebenenfalls umgedreht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Tja... die Interna des Java-Compilers und der VM sind für mich zwar keine Schwarze Magie :), dennoch muß ich gewisse Defizite zugeben...:( Vielleicht habe ich etwas zu viel mit C++ gearbeitet... Und trotzdem ist es gegen jegliche Logik (meiner Meinung nach), aber jetzt bin ich bereit aufzugeben...:uli

Vielen Dank

pecunia

Link zu diesem Kommentar
Auf anderen Seiten teilen

Servus,

ich glaub, ich blick grad nicht, was Ihr meint. Warum soll das eine Beispiel langsamer sein als das Andere? Abgesehen davon, dass es nicht kompiliert, weil die int-Arrays nicht als solche deklariert sind, und nicht durchläuft, weil das Array zu klein ist, laufen die zwei Beispiele bei mir in jeweils zwei Millisekunden durch (sagt System.currentTimeMillis(), ist zwar nur bedingt genau, aber immerhin).

Peter

Link zu diesem Kommentar
Auf anderen Seiten teilen

eine idee wäre

erste schleife 100 * 100 berechnung von Y *90

zweite schleife 100 berechnungen von y *90 (wenn der compiler es erkennt)

eine möglichkeit der änderung für den compiler

int array = new int[1000];

int z =0;

for(int y=0; y<100; y++)

z = y*90;

for(int x=0; x<100; x++)

array[x+z] = 1;

mfg

Link zu diesem Kommentar
Auf anderen Seiten teilen

...ist zwar nur bedingt genau...
Richtig, vergleichende Zeitmessungen mit einem int-Array der Größe 1000 durchzuführen halte ich auch nur für begenzt sinnvoll. Ein Array der Größenordnung 10^10 (oder besser 10^1000000, aber dabei befürchte ich, dass ein PC langsam zu streiken beginnt) wäre da schon etwas geeigneter. Größer ist eben besser.... ;)

Was die Arrays angeht, muss ich zustimmen, die heißen nur so, sind aber keine.

Außerdem sollte das Programm während der Laufzeit tatsächlich mit einer ArrayIndexOutOfBoundsException abfliegen. Denn aller spätestens bei x=100 und y=100 (und natürlich schon wesentlich früher, das werde ich jetzt aber trotz der einfachen Gegebenheiten nicht rechnen) wird der Schleifendurchlauf mit besagter Exception unterbrochen, da die Wertzuweisung des Arrays im Index

array[x + y * 90] = 1;  //  entspricht bei x=99,y=99 [B]array[99 + 99 * 90][/B]

                        //  -> bissel zu hoher Index
nimmer klappen kann. Wahrscheinlich meintest du für den Code im Schleifenköper eher
array[x + y * 9] = 1

Das sollte dann auch klappen, denke ich.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wahrscheinlich meintest du für den Code im Schleifenköper eher

array[x + y * 9] = 1

Hallo!

Klar, Du hast Recht... Ich habe dies nur als Beispiel geschrieben ohne weiter nachzudenken... und wollte wissen, wieso das eine schneller ablaufen soll als das andere... Man hat versucht mir das zu erklären... leider erfolglos...:confused:

Gruß aus der Rattenfängerstadt

pecunia

Link zu diesem Kommentar
Auf anderen Seiten teilen

die Interna des Java-Compilers und der VM sind für mich zwar keine Schwarze Magie, dennoch muß ich gewisse Defizite zugeben
Ich denke nicht, dass es hier wirklich den den Interna der Java VM liegt (der Compiler hat hier wenig bis gar nichts mit zu tun). Es liegt eher an der Tatsache, dass die Speicherverwaltung des Betriebssystems eher besser mit sequentiellen Zugriffen zurecht kommt. Ich habe gerade keinen C-Compiler vor Ort aber möchte fast wetten, dass das gleiche Beispiel in C oder C++ kompiliert auch kein anderes Laufzeitverhalten an den Tag legt.
Link zu diesem Kommentar
Auf anderen Seiten teilen

Ein Array der Größenordnung 10^10 (oder besser 10^1000000, aber dabei befürchte ich, dass ein PC langsam zu streiken beginnt) wäre da schon etwas geeigneter. Größer ist eben besser....

So, ich habe das Beispiel mal geringfügig aufgebohrt auf jeweils 10000 Schleifendurchläufe. Und selbst da ist das Ergebnis schon eindeutig. 2732ms für das erste, 545ms für das zweite Beispiel.

Man muss also die Werte nicht so irre hoch ansetzen.

Peter

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hab' jetzt auch mal Testläufe mit jeweils 10.000 Schleifendurchläufen durchgeführt.

  • II: 1.255.642.306ns
  • I: 1.095.678.625ns
  • II: 1.053.297.915ns
  • I: 1.104.121.772ns
  • I: 1.099.810.513ns
  • II: 1.058.374.581ns
  • II: 1.042.945.152ns
  • I: 1.095.298.441ns
  • I: 1.126.628.654ns
  • II: 1.696.484.319ns
  • II: 1.090.244.213ns
  • I: 1.100.406.348ns

Große Unterschiede kann ich nicht erkennen. Laut Laufzeittheorie sind beide Algorithmen der Ordnung x: n*x und daher äquivalent.

Link zu diesem Kommentar
Auf anderen Seiten teilen

1.5.0_05-b05 xp pro


public static void main(String args[]) throws SQLException {

		// Vorlauf damit zwischendurch nicht eine Hotspot optimierung dazwischenfunkt

		for (int i = 0; i < 100; i++) {

			int[] array = new int[1000];

			for (int x = 0; x < 100; x++)

				for (int y = 0; y < 100; y++)

					array[x + y * 9] = 1;

		}

		for (int i = 0; i < 100; i++) {

			int[] array = new int[1000];

			for (int y = 0; y < 100; y++)

				for (int x = 0; x < 100; x++)

					array[x + y * 9] = 1;

		}

		// Ab hier Messung

		double summe1 = 0;

		double summe2 = 0;

		for (int h = 0; h < 10; h++) {


			long start = System.currentTimeMillis();

			for (int i = 0; i < 10000; i++) {

				int[] array = new int[1000];

				for (int x = 0; x < 100; x++)

					for (int y = 0; y < 100; y++)

						array[x + y * 9] = 1;

			}

			long end1 = System.currentTimeMillis();


			for (int i = 0; i < 10000; i++) {

				int[] array = new int[1000];

				for (int y = 0; y < 100; y++)

					for (int x = 0; x < 100; x++)

						array[x + y * 9] = 1;

			}

			long end2 = System.currentTimeMillis();


			summe1 += (end1 - start);

			summe2 += (end2 - end1);

			System.out.println("Block1: " + (end1 - start));

			System.out.println("Block2: " + (end2 - end1));

		}

		System.out.println("Summe1: " + summe1);

		System.out.println("Summe2: " + summe2);

		System.out.println("Summe2 braucht "+summe2/summe1*100+"% der Zeit von Summe1");

	}

Link zu diesem Kommentar
Auf anderen Seiten teilen

Servus Jaraz,

scheint schon ein wenig an der VM zu liegen. :) Mit Deiner main-Methode hier meine Ergebnisse:


> java -classpath "$CLASSPATH:/Users/pgoetz/Documents/temp" -ms32m -mx32m SpeedTest

Block1: 1974

Block2: 482

Block1: 1977

Block2: 476

Block1: 1975

Block2: 478

Block1: 1971

Block2: 475

Block1: 1965

Block2: 475

Block1: 1968

Block2: 475

Block1: 1970

Block2: 477

Block1: 1972

Block2: 523

Block1: 2050

Block2: 484

Block1: 1991

Block2: 477

Summe1: 19813.0

Summe2: 4822.0

Summe2 braucht 24.337556150002523% der Zeit von Summe1

Peter

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...