Zu langsamer Methodenaufruf

Status
Nicht offen für weitere Antworten.

egrath

Aktives Mitglied
Hallo,

ich bin gerade dabei eine Doppelt Verkettete Liste zu schreiben (ja, ich weiss es gibt sowas schon fertig mitgeliefert; spiel mich nur etwas rum damit ;-)

Dabei habe ich das Problem, dass das einfügen von neuen Elementen relativ lange dauert (bei 10.000.000 Objekten ca. 15 sekunden). Ich konnte das Problem schon auf einen Methodenaufruf reduzieren, hab aber keinen Dau warum der so lange dauert - ein vorheriger, ähnlicher Methodenaufruf ist wesentlich kürzer.

Hier die Codezeile:

Code:
        public void insertFirst( T data )
        {
                ListElement<T> element = new ListElement<T>( startDummy_.getNextElement(), startDummy_, data );
                startDummy_.getNextElement().setPreviousElement( element );
                startDummy_.setNextElement( element );

                elementCount_ ++;
        }

Das setzen des vorherigen Elements (setPreviousElement) ist relativ schnell, das setzen des nächsten (setNextElement) langsam. Wenn ich zu testzwecken das letztere rausnehme brauchen 10.000.000 Methodenaufrufe nur ca. 1,5 Sekunden anstelle von 15.

Anbei der gesamte Quellcode - vielleicht hat ja jemand ne idee.

Danke und Grüsse,
Egon

ListElement.java:
Code:
package egrath.test.LinkedList;

public class ListElement<T>
{
        private ListElement next_;
        private ListElement prev_;
        private T data_;

        public ListElement( ListElement<T> next, ListElement<T> prev, T data )
        {
                next_ = next;
                prev_ = prev;
                data_ = data;
        }

        public ListElement<T> getPreviousElement()
        {
                return prev_;
        }

        public void setPreviousElement( ListElement<T> element )
        {
                prev_ = element;
        }

        public ListElement<T> getNextElement()
        {
                return next_;
        }

        public void setNextElement( ListElement<T> element )
        {
                next_ = element;
        }

        public void setData( T data )
        {
                data_ = data;
        }

        public T getData()
        {
                return data_;
        }
}

ListManager.java:
Code:
package egrath.test.LinkedList;

import java.util.Iterator;

public class ListManager<T>
implements Iterable<T>, Iterator<T>
{
        private ListElement<T> startDummy_;
        private ListElement<T> endDummy_;
        private ListElement<T> currentElement_;
        private int elementCount_;
        private int iterIndex_;
        private ListElement<T> iterElement_;

        public ListManager()
        {
                startDummy_ = new ListElement<T>( null, null, null );
                endDummy_ = new ListElement<T>( null, null, null );

                startDummy_.setNextElement( endDummy_ );
                endDummy_.setPreviousElement( startDummy_ );

                elementCount_ = 0;
        }

        public void insertLast( T data )
        {
                ListElement<T> element = new ListElement<T>( endDummy_, endDummy_.getPreviousElement(), data );
                endDummy_.getPreviousElement().setNextElement( element );
                endDummy_.setPreviousElement( element );

                elementCount_ ++;
        }

        public void insertFirst( T data )
        {
                ListElement<T> element = new ListElement<T>( startDummy_.getNextElement(), startDummy_, data );
                startDummy_.getNextElement().setPreviousElement( element );
                startDummy_.setNextElement( element );

                elementCount_ ++;
        }

        public void removeFirst()
        {
                startDummy_.getNextElement().getNextElement().setPreviousElement( startDummy_ );
                startDummy_.setNextElement( startDummy_.getNextElement().getNextElement() );

                elementCount_ --;
        }

        public void removeLast()
        {
                endDummy_.getPreviousElement().getPreviousElement().setNextElement( endDummy_ );
                endDummy_.setPreviousElement( endDummy_.getPreviousElement().getPreviousElement() );

                elementCount_ --;
        }

        public T getLast()
        {
                if( elementCount_ > 0 )
                        return endDummy_.getPreviousElement().getData();
                else
                        throw new IndexOutOfBoundsException( "No Elements in List" );
        }

        public T getFirst()
        {
                if( elementCount_ > 0 )
                        return startDummy_.getNextElement().getData();
                else
                        throw new IndexOutOfBoundsException( "No Elements in List" );
        }

        public T getIndex( int index )
        {
                return indexWorker( index, IndexWorkerAction.RETURN );
        }

        public void removeIndex( int index )
        {
                indexWorker( index, IndexWorkerAction.REMOVE );
        }

        private T indexWorker( int index, IndexWorkerAction action )
        {
                if( index > getLength() -1 )
                        throw new IndexOutOfBoundsException( String.format( "No element with given index (%d)", index ));

                ListElement<T> current = null;
                if( index > ( getLength() / 2 ))
                {
                        int currentIndex = getLength() -1;
                        current = endDummy_.getPreviousElement();
                        while( currentIndex > index )
                        {
                                current = current.getPreviousElement();
                                currentIndex --;
                        }
                }
                else
                {
                        int currentIndex = 0;
                        current = startDummy_.getNextElement();
                        while( currentIndex < index )
                        {
                                current = current.getNextElement();
                                currentIndex ++;
                        }
                }

                if( action == IndexWorkerAction.REMOVE )
                {
                        current.getPreviousElement().setNextElement( current.getNextElement() );
                        current.getNextElement().setPreviousElement( current.getPreviousElement() );
                        return null;
                }
                else if( action == IndexWorkerAction.RETURN )
                {
                        return current.getData();
                }

                return null;
        }

        public int getLength()
        {
                return elementCount_;
        }

        public void dumpList()
        {
                ListElement<T> current = startDummy_;
                while( current != null )
                {
                        System.out.println( current.getData() == null ? "NULL" : current.getData() );
                        current = current.getNextElement();
                }
        }

        private enum IndexWorkerAction
        {
                REMOVE,
                RETURN
        }

        // Implementation of Iterable and Iterator Interfaces
        public Iterator<T> iterator()
        {
                iterIndex_ = -1;
                iterElement_ = startDummy_;
                return this;
        }

        public boolean hasNext()
        {
                if( iterIndex_ < getLength() -1 )
                        return true;
                else
                        return false;
        }

        public T next()
        {
                iterIndex_ ++;
                iterElement_ = iterElement_.getNextElement();
                return iterElement_.getData();
        }

        public void remove()
        {
                removeIndex( iterIndex_ -1 );
        }
}

ListTest.java:
Code:
package egrath.test.LinkedList;

import java.util.Random;
import java.util.LinkedList;

public class ListTest
{
        private static final long ELEMENTS = 10000000;

        public static void main( String[] args )
        {
                ListManager<Integer> lm = new ListManager<Integer>();
                Random rnd = new Random();
                long myTime = 0;
                long sunTime = 0;

                /*
                ** Test for my implementation
                */

                // Testing insert
                long startTime = System.nanoTime();
                for( long i = 0; i < ELEMENTS; i ++ )
                {
                        lm.insertFirst( rnd.nextInt( 100 ) );
                }
                long endTime = System.nanoTime();
                myTime += (( endTime - startTime ) / 1000000 );
                System.out.println( "[MY]: Insert took: " + (( endTime - startTime ) / 1000000 ) + " ms" );

                // Testing get
                startTime = System.nanoTime();
                for( Integer i : lm )
                {
                }
                endTime = System.nanoTime();
                myTime += (( endTime - startTime ) / 1000000 );
                System.out.println( "[MY]: get took: " + (( endTime - startTime ) / 1000000 ) + " ms" );

                // Testing remove
                startTime = System.nanoTime();
                for( long i = 0; i < ELEMENTS; i ++ )
                        lm.removeFirst();
                endTime = System.nanoTime();
                myTime += (( endTime - startTime ) / 1000000 );
                System.out.println( "[MY]: remove took: " + (( endTime - startTime ) / 1000000 ) + " ms" );

                /*
                ** Test for Sun's implementation of the LinkedList
                */

                LinkedList<Integer> ll = new LinkedList<Integer>();
                startTime = System.nanoTime();
                for( long i = 0; i < ELEMENTS; i ++ )
                {
                        ll.addFirst( rnd.nextInt( 100 ));
                }
                endTime = System.nanoTime();
                sunTime += (( endTime - startTime ) / 1000000 );
                System.out.println( "[SUN]: Insert took: " + (( endTime - startTime ) / 1000000 ) + " ms" );

                startTime = System.nanoTime();
                for( Integer i : ll )
                {
                }
                endTime = System.nanoTime();
                sunTime += (( endTime - startTime ) / 1000000 );
                System.out.println( "[SUN]: get took: " + (( endTime - startTime ) / 1000000 ) + " ms" );

                startTime = System.nanoTime();
                for( long i = 0; i < ELEMENTS; i ++ )
                {
                        ll.removeFirst();
                }
                endTime = System.nanoTime();
                sunTime += (( endTime - startTime ) / 1000000 );
                System.out.println( "[SUN]: remove took: " + (( endTime - startTime ) / 1000000 ) + " ms" );

                // Print cummulative result
                System.out.println( String.format( "My: %d        Sun: %d", myTime, sunTime ));
        }
}
 

schalentier

Gesperrter Benutzer
Also der Code sieht gut aus.

Bei mir siehts wie folgt aus:

Code:
[MY]: Insert took: 5210 ms
[MY]: get took: 259 ms
[MY]: remove took: 315 ms
[SUN]: Insert took: 3724 ms
[SUN]: get took: 241 ms
[SUN]: remove took: 558 ms
My: 5784        Sun: 4523

Fuehre ich erst SUN und dann deinen Code aus:

Code:
[SUN]: Insert took: 5312 ms
[SUN]: get took: 246 ms
[SUN]: remove took: 450 ms
[MY]: Insert took: 3511 ms
[MY]: get took: 228 ms
[MY]: remove took: 301 ms
My: 4040        Sun: 6008

Man sieht, am Anfang hat die VM noch nicht genug Speicher, muss diesen also erstmal anfordern. Nebenbei laeuft aber schon dein Minibenchmark und verfaelscht damit die Ergebnisse...

Insgesamt ist dein Code aber schneller. Gratulation :-D
 

egrath

Aktives Mitglied
Hallo,

ah ok an das Problem dass die VM beim starten noch nicht genug Speicher allokiert hat habe ich nicht gedacht - Danke für den Tipp!

Grüsse, Egon
 

Marco13

Top Contributor
Der Just-InTime-Compiler tut aber auch noch was. Wenn man die ELEMENTS z.B. in einer Schleife von 10000 in *10-Schritten bis 10000000 laufen läßt, nähern sich die Ergebnisse schon ziemlich an. Und spätestens, wenn man den Just-In-Time-Compiler dektiviert, sind die Zeiten praktisch gleich.
 

egrath

Aktives Mitglied
Nur stellt sich die Frage: In welcher Situation deaktiviert man den JIT schon - eine Applikation sollte eigentlich immer mit maximaler Performance laufen und die kriegt man nur über den JIT.

Grüsse,
Egon
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
E Threads Ausführung in Threads ist langsamer als ohne Threads Allgemeine Java-Themen 13
S Threads Multithreading- langsamer als Singlethreading-Programm Allgemeine Java-Themen 6
M Rechnen mit kleinen Zahlen langsamer!? Allgemeine Java-Themen 11
A Rekursives Programm wird immer langsamer Allgemeine Java-Themen 10
M Methodenaufrufe sind über Interfaces langsamer. Allgemeine Java-Themen 43
G Programm wird immer langsamer Allgemeine Java-Themen 7
S Web Applikation wird immer langsamer Allgemeine Java-Themen 5
K Zu viele Threads -> langsamer angehen. Allgemeine Java-Themen 3
M Thymleaf Methodenaufruf Allgemeine Java-Themen 4
K Methodenaufruf mit String / String zu Objekt konvertieren Allgemeine Java-Themen 8
A Methodenaufruf funktioniert nicht richtig Allgemeine Java-Themen 5
mrbig2017 Kapselung Methodenaufruf in DLL schlägt fehl! Allgemeine Java-Themen 1
S Methodenaufruf in Unterklassen Allgemeine Java-Themen 3
F Methodenaufruf mit abgeleiteter Klasse als Arg... Allgemeine Java-Themen 10
O Zeitbedingter Methodenaufruf Allgemeine Java-Themen 1
C Objekt Datenverlust nach Methodenaufruf Allgemeine Java-Themen 9
D Frage und Antwort Programm, Problem bei Methodenaufruf Allgemeine Java-Themen 3
127.0.0.1 Methodenaufruf -cannot find symbol- Allgemeine Java-Themen 14
S Methoden Unerwarteter Methodenaufruf Allgemeine Java-Themen 5
T Polymorphie Statischer Methodenaufruf einer Kindsklasse Allgemeine Java-Themen 4
pg1337 Methodenaufruf Allgemeine Java-Themen 22
D Vererbung, Reflection und automatischer Methodenaufruf Allgemeine Java-Themen 24
R Java Parameterabfrage bei Methodenaufruf Allgemeine Java-Themen 4
MQue Performance Methodenaufruf - if Abfrage Allgemeine Java-Themen 19
B Problem mit Methodenaufruf in Konstruktor Allgemeine Java-Themen 6
S Bekomme nullwerte bei methodenaufruf in versch. Klassen Allgemeine Java-Themen 16
W Sequentieller Methodenaufruf -> UML Allgemeine Java-Themen 10
G [Reflection + WebService] Methodenaufruf an einem Proxy Allgemeine Java-Themen 11
S Methodenaufruf per String? Allgemeine Java-Themen 4
G Fehler bei Methodenaufruf Allgemeine Java-Themen 30
P Methodenaufruf von catch Allgemeine Java-Themen 2
MQue Methodenaufruf auf der Insel Allgemeine Java-Themen 4
MQue Methodenaufruf von wem? Allgemeine Java-Themen 11
N Methodenaufruf wiederholbar machen? Allgemeine Java-Themen 2
H Methodenaufruf Allgemeine Java-Themen 5
D Probleme mit Methodenaufruf von Klasse in dll (jni) Allgemeine Java-Themen 19
M Vergleich im geordeten Vector und Methodenaufruf Allgemeine Java-Themen 2
byte Methodenaufruf per Reflection? Allgemeine Java-Themen 2
B Methodenaufruf Allgemeine Java-Themen 6
S Methodenaufruf Allgemeine Java-Themen 4

Ähnliche Java Themen

Neue Themen


Oben