2016-09-26 4 views
2

Ich habe versucht, die Leistung meines benutzerdefinierten Iterators über ein einfaches int-Array zu messen. Es ist wirklich einfach, wie unten dargestellt:Benutzerdefinierter Iterator ist langsam

class IntArrayIterator_NoCheck implements Iterator<Integer> { 

    private final int[] array; 
    private int counter = 0; 

    public IntArrayIterator_NoCheck(int[] array) { 
     this.array = array; 
    } 

    @Override 
    public boolean hasNext() { 
     return counter < array.length; 
    } 

    @Override 
    public Integer next() { 
     return array[counter++]; 
    } 

} 

Nach dem Vergleich Iterator und Trove (http://trove.starlight-systems.com/) zu Arraylist, fand ich seltsame Ergebnisse. Der Test wurde in der folgenden Art und Weise durchgeführt:

  • List/Array von 100000 Zufalls int Elemente
  • WarmUp
    • 10000X Iterieren über ganze Kollektion
    • 10000X Iterieren über ganze Kollektion wieder
  • Test
    • 10000x Iterieren über ganze Sammlung, über System.nanoTime UND ThreadMXBean.getCurrentThreadCpuTime() Messen

Die Trove TIntArrayList Iterator ist die schnellste mit 30 ms Laufzeit. Der Java ArrayList-Iterator hatte eine Laufzeit von 85 ms. Der benutzerdefinierte Iterator über dem einfachen int-Array hatte 320 ms Laufzeit!

Was ist der mögliche Grund für die schreckliche Leistung meines benutzerdefinierten Iterators? Nach der Überprüfung der Iterator-Implementierungen von ArrayList und TIntArrayList sind sie viel komplexer (führen mehr Operationen aus), weshalb ich nicht verstehe, warum sie schneller ist. Könnte mir bitte jemand das erklären?

+0

Schreiben Sie Benchmark-Code nicht manuell, verwenden Sie JMH: http://openjdk.java.net/projects/code-tools/jmh/ – leventov

+0

Vielen Dank für den Vorschlag! Ich werde es mir ansehen. –

Antwort

4

Ihre next Methode wird die gleiche Bytecode wie

public Integer next() { 
    return Integer.valueOf(array[counter++]); 
} 

Hinweis erzeugt, dass für jeden int außerhalb des Bereichs der im Cache gespeicherten Werte (nur -128 zu 127 sein guarantied) ein neues Integer Objekt erstellt wird.

Dies passiert nicht für ArrayList, da die Konvertierung vor dem Speichern der Integer s in der Liste passiert.
TArrayList hat a custom iterator type, die den primitiven Typ gibt int, die nicht die Schaffung eines Objekts Integer erfordert.

+0

Danke! Das habe ich überhaupt nicht bemerkt. –

3

Sie haben einen Iterator von Integer da, aber Sie werden eine Reihe von int verwenden.

Sie tun also konstant Unboxing beim Iterieren. Wissen Sie; Integer in Inte und Back zu verwandeln ist eine kostspielige Operation; und das für jede Iteration tun ist Sie zu töten.

Wie jeder Anruf an nächste bedeutet Boxen ein Int in Integer.