1. Въведение
В този урок ще разгледаме библиотеката FastUtil .
Първо ще кодираме няколко примера за специфичните за него колекции.
След това ще анализираме производителността, която дава името на FastUtil .
И накрая, нека да вземе един поглед на FastUtil е BigArray комунални услуги.
2. Характеристики
В FastUtil Java библиотеката се стреми да разшири рамката на Java колекции. Той осигурява специфични за типа карти, набори, списъци и опашки с по-малък отпечатък на паметта и бърз достъп и вмъкване. FastUtil също така предоставя набор от помощни програми за работа и манипулиране на големи (64-битови) масиви, набори и списъци.
Библиотеката включва и множество практически класове за въвеждане / извеждане за двоични и текстови файлове.
Последната му версия, FastUtil 8, също пусна множество специфични за типа функции, разширявайки функционалните интерфейси на JDK .
2.1. Скорост
В много случаи реализациите на FastUtil са най-бързите от наличните. Авторите дори са предоставили свой собствен задълбочен доклад за сравнение, сравнявайки го с подобни библиотеки, включващи HPPC и Trove.
В този урок ще търсим да дефинираме собствените си еталони, използвайки Java Microbench Harness (JMH).
3. Пълноразмерна зависимост
На върха на обичайното за JUnit зависимостта, ние ще се използва най- FastUtils и JMH зависимости в този урок.
Ще ни трябват следните зависимости в нашия файл pom.xml :
it.unimi.dsi fastutil 8.2.2 org.openjdk.jmh jmh-core 1.19 test org.openjdk.jmh jmh-generator-annprocess 1.19 test
Или за потребители на Gradle:
testCompile group: 'org.openjdk.jmh', name: 'jmh-core', version: '1.19' testCompile group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.19' compile group: 'it.unimi.dsi', name: 'fastutil', version: '8.2.2'
3.1. Персонализиран Jar файл
Поради липсата на генерични продукти, FastUtils генерира голям брой специфични за типа класове. И за съжаление, това води до огромен jar файл.
За наш късмет обаче FastUtils включва скрипт find-deps.sh, който позволява генериране на по-малки, по-фокусирани буркани, състоящи се само от класовете, които искаме да използваме в нашето приложение.
4. Колекции, специфични за типа
Преди да започнем, нека да надникнем набързо в простия процес на създаване на екземпляр на специфична за типа колекция. Нека да изберем HashMap, която съхранява ключове и стойности с помощта на двойни.
За тази цел FastUtils осигурява Double2DoubleMap интерфейс и Double2DoubleOpenHashMap изпълнение:
Double2DoubleMap d2dMap = new Double2DoubleOpenHashMap();
Сега, когато създадохме пример за нашия клас, можем просто да попълним данни, както бихме направили с всяка карта от API на Java Collections:
d2dMap.put(2.0, 5.5); d2dMap.put(3.0, 6.6);
И накрая, можем да проверим дали данните са добавени правилно:
assertEquals(5.5, d2dMap.get(2.0));
4.1. производителност
FastUtils се фокусира върху изпълнението си. В този раздел ще използваме JMH, за да потвърдим този факт. Нека сравнимвнедряванетона Java Collections HashSet с IntOpenHashSet на FastUtil .
Първо, нека видим как да приложим IntOpenHashSet:
@Param({"100", "1000", "10000", "100000"}) public int setSize; @Benchmark public IntSet givenFastUtilsIntSetWithInitialSizeSet_whenPopulated_checkTimeTaken() { IntSet intSet = new IntOpenHashSet(setSize); for(int i = 0; i < setSize; i++) { intSet.add(i); } return intSet; }
Над, ние сме просто обявява IntOpenHashSet изпълнението на IntSet интерфейс. Също така декларирахме началния размер setSize с анотацията @Param .
Казано по-просто, тези числа се подават в JMH, за да се получат поредица тестове за сравнение с различни размери.
След това нека направим същото, като използваме внедряването на Java Collections:
@Benchmark public Set givenCollectionsHashSetWithInitialSizeSet_whenPopulated_checkTimeTaken() { Set intSet = new HashSet(setSize); for(int i = 0; i < setSize; i++) { intSet.add(i); } return intSet; }
И накрая, нека стартираме бенчмарка и сравним двете имплементации:
Benchmark (setSize) Mode Cnt Score Units givenCollectionsHashSetWithInitialSizeSet... 100 avgt 2 1.460 us/op givenCollectionsHashSetWithInitialSizeSet... 1000 avgt 2 12.740 us/op givenCollectionsHashSetWithInitialSizeSet... 10000 avgt 2 109.803 us/op givenCollectionsHashSetWithInitialSizeSet... 100000 avgt 2 1870.696 us/op givenFastUtilsIntSetWithInitialSizeSet... 100 avgt 2 0.369 us/op givenFastUtilsIntSetWithInitialSizeSet... 1000 avgt 2 2.351 us/op givenFastUtilsIntSetWithInitialSizeSet... 10000 avgt 2 37.789 us/op givenFastUtilsIntSetWithInitialSizeSet... 100000 avgt 2 896.467 us/op
Тези резултати показват, че внедряването на FastUtils е много по-ефективно от алтернативата на Java Collections.
5. Големи колекции
Друга важна характеристика на Fa stUtils е възможността да се използват 64-битови масиви. Масивите в Java по подразбиране са ограничени до 32 бита.
За да започнем, нека разгледаме класа BigArrays за Integer типове. IntBigArrays предоставя статични методи за работа с двумерни масиви Integer . Използвайки тези предоставени методи, ние можем по същество да обгърнем нашия масив в по-лесен за ползване едноизмерен масив.
Нека да разгледаме как работи това.
Първо, ще започнем с инициализиране на едноизмерен масив и превръщането му в двуизмерен масив с помощта на метода за обгръщане на IntBigArray :
int[] oneDArray = new int[] { 2, 1, 5, 2, 1, 7 }; int[][] twoDArray = IntBigArrays.wrap(oneDArray.clone());
Трябва да се погрижим да използваме метода на клониране , за да осигурим дълбоко копие на масива.
Сега, както бихме направили със списък или карта , можем да получим достъп до елементите, използвайки метода get :
int firstIndex = IntBigArrays.get(twoDArray, 0); int lastIndex = IntBigArrays.get(twoDArray, IntBigArrays.length(twoDArray)-1);
И накрая, нека добавим няколко проверки, за да сме сигурни, че нашият IntBigArray връща правилните стойности:
assertEquals(2, firstIndex); assertEquals(7, lastIndex);
6. Заключение
В тази статия се потопихме в основните функции на FastUtils .
Разгледахме някои от специфичните за типа колекции, които FastUtil предлага, преди да си поиграем с някои BigCollections .
Както винаги, кодът може да бъде намерен в GitHub