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
:
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.2.2</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.33</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.33</version>
<scope>test</scope>
</dependency>
Или для пользователей 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
, который позволяет генерировать меньшие, более целенаправленные jar-файлы, содержащие только те классы, которые мы хотим использовать в нашем приложении.
4. Коллекции для конкретных типов
Прежде чем мы начнем, давайте кратко рассмотрим простой процесс создания коллекции для определенного типа . Давайте выберем HashMap
, в котором ключи и значения хранятся с использованием двойных значений.
Для этой цели FastUtils
предоставляет интерфейс Double2DoubleMap и реализацию
Double2DoubleOpenHashMap
:
Double2DoubleMap d2dMap = new Double2DoubleOpenHashMap();
Теперь, когда мы создали экземпляр нашего класса, мы можем просто заполнить данные, как и любую карту
из API коллекций Java:
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<Integer>
с 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:
@Benchmark
public Set<Integer> givenCollectionsHashSetWithInitialSizeSet_whenPopulated_checkTimeTaken() {
Set<Integer> 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
для целочисленных
типов. IntBigArrays
предоставляет статические методы для работы с двумерными целочисленными
массивами. Используя эти предоставленные методы, мы можем по существу обернуть наш массив в более удобный одномерный массив.
Давайте посмотрим, как это работает.
Во-первых, мы начнем с инициализации одномерного массива и преобразования его в двумерный массив с помощью метода переноса 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.