私はGapBufferリストをJavaで実装しましたが、なぜこのようなパフォーマンスの低下が起こっているのかわかりません。 C#で書かれた同様のコードは期待通りに動作します。リストの中央に挿入すると、C#のリストの実装よりもはるかに高速です。しかし、Javaのバージョンは奇妙な動作をしています。ここでJavaでの予期しないパフォーマンスの低下
いくつかのベンチマーク情報です:
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.
あなたが見ることができるように、あなたがリストの先頭に挿入すると、ギャップバッファが期待通りに動作します。それは、ArrayListをより多くの、多くの、何回も優れています。しかし、リスト内の任意の場所に挿入したり削除したりするとき、ギャップバッファーには私が説明できない奇妙なパフォーマンスのペナルティがあります。見知らぬ人でも、GapBufferListから項目を削除するのは、項目を追加するよりも遅いということです。これまで実行したすべてのテストでは、項目を削除するのに約3倍の時間がかかります。
@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];
}
ギャップバッファのコードがhereで見つけることができ、及びベンチマークエントリポイントのコードがhere見出すことができる:それらのコードがほぼ同じです。 Flow.***Exception
への参照をRuntimeException
に置き換えることができます。
これはArrayListよりも遅い理由の一部を説明していますが、 'remove'関数が' add'関数の3倍遅い理由ではありません。なぜこれが分かっていますか? – aboveyou00
同じ理由で、ArrayListもremoveで同じメソッドを使用しています。 – Thihara
OK、私はSystem.arraycopyに切り替えると、 'remove'と' add'の変則的なペナルティが取り除かれたので、これを答えとして受け入れました。私はまだ最初にそのようなペナルティがあった理由を知りたいが、今は問題がなくなっている。ご回答有難うございます! – aboveyou00