Я написал тест, который пытается проверить две вещи:
- Независимо от того, влияет ли размер массива буферов на его производительность, даже если вы не используете весь буфер
- Относительная производительность массивов и
ArrayList
Я был удивлен результатами
- В штучной упаковке массивы (т.е.
Integer
vsint
) не намного медленнее, чем примитивная версия - Размер базового массива не имеет большого значения.
-
ArrayList
более чем в два раза медленнее соответствующего массива.
Вопросы
- Почему
ArrayList
намного медленнее? - Хорошо ли работает мой бенчмарк? Другими словами, мои результаты точны?
Результаты
0% Scenario{vm=java, trial=0, benchmark=SmallArray} 34.57 ns; ?=0.79 ns @ 10 trials
17% Scenario{vm=java, trial=0, benchmark=SmallBoxed} 40.40 ns; ?=0.21 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=SmallList} 105.78 ns; ?=0.09 ns @ 3 trials
50% Scenario{vm=java, trial=0, benchmark=BigArray} 34.53 ns; ?=0.05 ns @ 3 trials
67% Scenario{vm=java, trial=0, benchmark=BigBoxed} 40.09 ns; ?=0.23 ns @ 3 trials
83% Scenario{vm=java, trial=0, benchmark=BigList} 105.91 ns; ?=0.14 ns @ 3 trials
benchmark ns linear runtime
SmallArray 34.6 =========
SmallBoxed 40.4 ===========
SmallList 105.8 =============================
BigArray 34.5 =========
BigBoxed 40.1 ===========
BigList 105.9 ==============================
vm: java
trial: 0
Код
Этот код был написан в Windows с использованием Java 7 и Google caliper 0.5-rc1 (потому что последнее, что я проверил 1.0, еще не работает в Windows).
Краткое описание: во всех 6 тестах на каждой итерации цикла он добавляет значения в первые 128 ячеек массива (независимо от того, насколько велик массив) и добавляет это к общему значению. Caliper сообщает мне, сколько раз тест должен выполняться, поэтому я повторяю это дополнение 128 раз.
6 тестов имеют большую (131072) и небольшую (128) версию int[]
, Integer[]
и ArrayList<Integer>
. Вероятно, вы можете определить, что из имен.
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
public class SpeedTest {
public static class TestBenchmark extends SimpleBenchmark {
int[] bigArray = new int[131072];
int[] smallArray = new int[128];
Integer[] bigBoxed = new Integer[131072];
Integer[] smallBoxed = new Integer[128];
List<Integer> bigList = new ArrayList<>(131072);
List<Integer> smallList = new ArrayList<>(128);
@Override
protected void setUp() {
Random r = new Random();
for(int i = 0; i < 128; i++) {
smallArray[i] = Math.abs(r.nextInt(100));
bigArray[i] = smallArray[i];
smallBoxed[i] = smallArray[i];
bigBoxed[i] = smallArray[i];
smallList.add(smallArray[i]);
bigList.add(smallArray[i]);
}
}
public long timeBigArray(int reps) {
long result = 0;
for(int i = 0; i < reps; i++) {
for(int j = 0; j < 128; j++) {
result += bigArray[j];
}
}
return result;
}
public long timeSmallArray(int reps) {
long result = 0;
for(int i = 0; i < reps; i++) {
for(int j = 0; j < 128; j++) {
result += smallArray[j];
}
}
return result;
}
public long timeBigBoxed(int reps) {
long result = 0;
for(int i = 0; i < reps; i++) {
for(int j = 0; j < 128; j++) {
result += bigBoxed[j];
}
}
return result;
}
public long timeSmallBoxed(int reps) {
long result = 0;
for(int i = 0; i < reps; i++) {
for(int j = 0; j < 128; j++) {
result += smallBoxed[j];
}
}
return result;
}
public long timeBigList(int reps) {
long result = 0;
for(int i = 0; i < reps; i++) {
for(int j = 0; j < 128; j++) {
result += bigList.get(j);
}
}
return result;
}
public long timeSmallList(int reps) {
long result = 0;
for(int i = 0; i < reps; i++) {
for(int j = 0; j < 128; j++) {
result += smallList.get(j);
}
}
return result;
}
}
public static void main(String[] args) {
Runner.main(TestBenchmark.class, new String[0]);
}
}