2017-01-21 5 views
2

Ich habe versucht herauszufinden, was der schnellste Weg ist, um eine Liste von ganzen Zahlen zusammenzufassen.Was ist der schnellste Weg, um eine Interger Liste zusammenzufassen

Zunächst einmal habe ich eine Methode, die Sampledaten liefert:

public static List<Integer> getIntList(int size) { 
    LinkedList<Integer> sampleList = new LinkedList<>(); 
    Random rand = new Random(); 
    rand.ints(size).forEach((num)-> sampleList.add(num)); 
    return sampleList; 
} 

Dann habe ich einige verschiedene Möglichkeiten tryed die Liste zusammenzufassen. Zunächst einmal das Schlimmste ein:

public static void sumUpWithForLoop(List<Integer> data) { 
    System.out.println("For-loop:"); 
    long start = System.currentTimeMillis(); 
    int listLenght = data.size(); 
    int total = 0; 
    for (int i = 0; i < listLenght; i++) { 
     total += data.get(i); 
    } 
    long end = System.currentTimeMillis(); 
    System.out.println("Result: " + total); 
    System.out.println("Duration: " + (end - start) + "ms"); 
} 

Nach dem Ausführen dieser Klasse i bemerkt habe, dass es wirklich langsam ist, weil es immer get(index) verwendet, die ziemlich lange dauert.

Wege, dass ich tryed die Liste mit einem Iterator zusammenzufassen

public static void sumUpWithItterator(List<Integer> data) { 
    System.out.println("Iterator:"); 
    long start = System.currentTimeMillis(); 
    int total = 0; 
    for (Integer num : data) { 
     total += num; 
    } 
    long end = System.currentTimeMillis(); 
    System.out.println("Result: " + total); 
    System.out.println("Duration: " + (end - start) + "ms"); 
} 

Diese Methode ist der schnellste Weg, um eine Integer-Liste so weit zu fassen, aber ich versuche immer noch schneller zu finden. Ich habe versucht auch .stream() und .parallelStream() zu verwenden: als der Iterator

public static void sumUpWithNormalStream(List<Integer> data) { 
    System.out.println("Stream"); 
    long start = System.currentTimeMillis(); 
    int total = data.stream().mapToInt(num -> num).sum(); 
    long end = System.currentTimeMillis(); 
    System.out.println("Result: " + total); 
    System.out.println("Duration: " + (end - start) + "ms"); 
} 
public static void sumUpWithParallelStream(List<Integer> data) { 
    System.out.println("ParallelStream"); 
    long start = System.currentTimeMillis(); 
    int total = data.parallelStream().mapToInt(num->num).sum(); 
    long end = System.currentTimeMillis(); 
    System.out.println("Result: " + total); 
    System.out.println("Duration: " + (end - start) + "ms"); 
} 

Die normalen stream ist fast so schnell wie der Iterator, während die parallelStream ist viel langsamer. Ich nehme an, dass dies durch den Overhead der Parallelisierung und die Tatsache verursacht wird, dass das Zusammenfassen einer Liste eine Operation ist, die ziemlich schnell abläuft und nicht auf Dinge wie Datenbankoperationen warten muss.

Alles in allem bin ich immer noch nicht glücklich mit der aktuellen Methode, aber ich habe noch keine schnellere gefunden. Haben Sie irgendwelche Ideen, was schneller sein könnte als ein normaler Iterator zum Zusammenfassen einer Liste?

Vielen Dank für Ihre Anregungen.

+7

Hinzufügen von Zahlen ist spottbillig. Ihre ganze Zeit wird damit verbracht, Zeiger zu verfolgen, temporäre Objekte zu erstellen und Zwischenfunktionen aufzurufen. Versuchen Sie 'ArrayList ' oder sogar 'int []' zu verwenden - es sollte viel schneller sein. –

+0

Der schnellste ist eine native Methode. –

+4

Muss es "Integer's sein? Können Sie nicht beispielsweise ein Array von 'int' verwenden, um die Kosten für das automatische Unboxing zu vermeiden? –

Antwort

2

In Ihrem Beispiel ist der Speicherzugriff wahrscheinlich ein Flaschenhals, da das Hinzufügen eines Integer sehr schnell ist, aber der Zugriff auf das nächste Element der verknüpften Liste zwei Speicherzugriffe erfordert (einen für den nächsten Knoten und einen für den Zugriff auf ganzzahlige Werte) Unboxed-Wert verwenden). Beachten Sie auch, dass die verkettete Liste wahrscheinlich über den Speicher verstreut ist, so dass es eine hohe Wahrscheinlichkeit für einen Cache-Fehler gibt.

Um es schneller zu machen, sollten Sie den Speicherzugriffsaufwand reduzieren. Änderung von LinkedList zu ArrayList würde einzelnen Zugriff (auf zufälligen Speicherort im Speicher) entfernen. Die Änderung von ArrayList zu Raw-Array würde die zweite Zeile entfernen, da in diesem Fall nicht geblockte Ganzzahlen im Speicher abgelegt werden.

So sollte die Version basierend auf int[] am schnellsten sein (jedoch weniger flexibel als ArrayList<Integer> Version).

1

Mit ArrayList<Integer> anstelle von LinkedList<integer> werden Sie wahrscheinlich bessere Ergebnisse erzielen. Und da der Zugriff auf Elemente einzeln am schnellsten erfolgt, wenn diese Elemente im RAM nebeneinander gespeichert werden, versuchen Sie es mit int[].

Im Allgemeinen, wenn Sie die Leistung eines Programms steigern möchten, versuchen Sie, alle Funktionsaufrufe oder High-Level-Code durch Iterationen und Low-Level-Code zu ersetzen. Das sollte die Leistung deutlich verbessern.

Verwandte Themen