Ich habe eine GapBuffer-Liste in Java implementiert, und ich kann nicht herausfinden, warum es eine solche Leistungseinbuße bekommt. Ähnlicher in C# geschriebener Code verhält sich wie erwartet: Das Einfügen in die Mitte der Liste ist viel schneller als die Implementierung von List in C#. Aber die Java-Version verhält sich merkwürdig.Unerwarteter Performance-Nachteil in Java
Hier einige Benchmark-Informationen:
Adding/removing 10,000,000 items @ the end of the dynamic array...
ArrayList: 683 milliseconds
GapBufferList: 416 milliseconds
Adding/removing 100,000 items @ a random spot in the dynamic array...
- ArrayList add: 721 milliseconds
- ArrayList remove: 612 milliseconds
ArrayList: 1333 milliseconds
- GapBufferList add: 1293 milliseconds
- GapBufferList remove: 2775 milliseconds
GapBufferList: 4068 milliseconds
Adding/removing 100,000 items @ the beginning of the dynamic array...
ArrayList: 2422 milliseconds
GapBufferList: 13 milliseconds
Clearly, the GapBufferList is the better option.
Wie Sie sehen können, wenn Sie an den Anfang der Liste einfügen, verhält sich die Lücke Puffer wie erwartet: es viele, viele, viele Male besser als Arraylist ist . Beim Einfügen und Entfernen an einer zufälligen Stelle in der Liste hat der Lückenpuffer jedoch eine merkwürdige Leistungseinbuße, die ich nicht erklären kann. Noch seltsamer ist die Tatsache, dass das Entfernen von Objekten aus der GapBufferList langsamer ist als das Hinzufügen von Objekten - nach jedem Test, den ich bisher ausgeführt habe, dauert das Entfernen eines Objekts etwa dreimal länger als das Hinzufügen eines Elements fast identisch, dass ihr Code ist:
@Override
public void add(int index, T t)
{
if (index < 0 || index > back.length - gapSize) throw new IndexOutOfBoundsException();
if (gapPos > index)
{
int diff = gapPos - index;
for (int q = 1; q <= diff; q++)
back[gapPos - q + gapSize] = back[gapPos - q];
}
else if (index > gapPos)
{
int diff = gapPos - index;
for (int q = 0; q < diff; q++)
back[gapPos + q] = back[gapPos + gapSize + q];
}
gapPos = index;
if (gapSize == 0) increaseSize();
back[gapPos++] = t; gapSize--;
}
@Override
public T remove(int index)
{
if (index < 0 || index >= back.length - gapSize) throw new IndexOutOfBoundsException();
if (gapPos > index + 1)
{
int diff = gapPos - (index + 1);
for (int q = 1; q <= diff; q++)
back[gapPos - q + gapSize] = back[gapPos - q];
}
else
{
int diff = (index + 1) - gapPos;
for (int q = 0; q < diff; q++)
back[gapPos + q] = back[gapPos + gapSize + q];
}
gapSize++;
return back[gapPos = index];
}
der Code für die Lücke Puffer kann für den Benchmark Einstiegspunkt zu finden ist here bei here und der Code zu finden. (Sie können einen beliebigen Verweis auf Flow.***Exception
durch RuntimeException
ersetzen.)
OK, danke, das erklärt, warum es langsamer als ArrayList ist, aber nicht warum die 'remove' Funktion dreimal langsamer ist als die' add' Funktion. Weißt du warum das so ist? – aboveyou00
Gleicher Grund, ArrayList verwendet die gleiche Methode auch in remove. – Thihara
OK, ich akzeptiere dies als Antwort, denn sobald ich zu System.arraycopy gewechselt habe, wurde die seltsame Strafe in 'remove' gegenüber' add' entfernt. Ich würde immer noch gerne wissen, warum es eine solche Strafe gab, aber jetzt ist das Problem vorbei. Danke für deine Antwort! – aboveyou00