1. 소개

이 사용방법(예제)에서는 FastUtil  라이브러리를 살펴보겠습니다.

먼저 유형별 컬렉션 의 몇 가지 예를 코딩합니다 .

그런 다음 FastUtil  에 이름 을 부여하는 성능을 분석합니다.

마지막으로 FastUtil 의  BigArray  유틸리티를 살펴보겠습니다.

2. 특징

FastUtil Java 라이브러리는 Java Collections Framework를 확장하려고 합니다 . 더 작은 메모리 공간과 빠른 액세스 및 삽입으로 유형별 맵, 세트, ​​List 및 Queue 을 제공 합니다. FastUtil  은 대형(64비트) 어레이, 세트 및 List을 사용하고 조작하기 위한 유틸리티 세트도 제공 합니다.

라이브러리에는 바이너리 및 텍스트 파일을 위한 다수의 실용적인 입/출력 클래스 도 포함되어 있습니다.

최신 릴리스인 FastUtil 8 은 JDK의 기능 인터페이스 를 확장하는 다양한 유형별 기능 도 릴리스했습니다 .

2.1. 속도

대부분의 경우  FastUtil  구현이 가장 빠릅니다. 작성자는 HPPC  및  Trove 와 같은 유사한 라이브러리와 비교하여 자체 심층 벤치마크 보고서 를 제공하기도 했습니다.

이 사용방법(예제)에서는 JMH(Java Microbench Harness) 를 사용하여 고유한 벤치마크를 정의하는 방법을 살펴보겠습니다 .

3. 완전한 크기의 의존성

 이 사용방법(예제) 에서는 일반적인 JUnit 의존성 외에 FastUtilsJMH 의존성 을 사용할 것입니다.

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.35</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.35</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. Custom형 Jar 파일

제네릭이 없기 때문에  FastUtils  는 많은 수의 유형별 클래스를 생성합니다. 불행히도 이것은 거대한 jar 파일로 이어집니다.

그러나 다행 스럽게도 FastUtils  에는 응용 프로그램에서 사용하려는 클래스로만 구성된 더 작고 집중된 jar를 생성할 수 있는 find-deps.sh  스크립트가 포함되어 있습니다.

4. 유형별 컬렉션

시작하기 전에 유형별 컬렉션을 인스턴스화하는 간단한 프로세스를 간단히 살펴보겠습니다 . double  을 사용하여 키와 값을 저장 하는 HashMap 을 선택해 보겠습니다 .

이를 위해  FastUtils Double2DoubleMap  인터페이스와  Double2DoubleOpenHashMap  구현을 제공합니다.

Double2DoubleMap d2dMap = new Double2DoubleOpenHashMap();

이제 클래스를 인스턴스화했으므로 Java Collections API에서 Map  으로 데이터를 채울 수 있습니다  .

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> 구현을  FastUtil의  IntOpenHashSet 과 비교해 봅시다 .

먼저  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; 
}

위에서 IntSet  인터페이스 의 IntOpenHashSet 구현을  간단히 선언했습니다 . 또한 @Param  어노테이션 을 사용하여  초기 크기  setSize  를 선언했습니다.

간단히 말해서, 이러한 수치는 JMH에 입력되어 다양한 세트 크기로 일련의 벤치마크 테스트를 생성합니다.

다음으로 Java Collections 구현을 사용하여 동일한 작업을 수행해 보겠습니다.

@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비트로 제한됩니다.

시작하려면 Integer 유형 에 대한 BigArrays 클래스를 살펴보겠습니다 . IntBigArrays 는 2차원 정수 배열 작업을 위한 정적 메서드를 제공합니다. 이러한 제공된 방법을 사용하여 기본적으로 배열을 보다 사용자 친화적인 1차원 배열로 래핑할 수 있습니다.

이것이 어떻게 작동하는지 살펴보겠습니다.

먼저 1차원 배열을 초기화하고 IntBigArray의 wrap  메서드를 사용하여 2차원 배열로 변환합니다.

int[] oneDArray = new int[] { 2, 1, 5, 2, 1, 7 };
int[][] twoDArray = IntBigArrays.wrap(oneDArray.clone());

복제 방법을 사용 하여 어레이의 전체 복사본을 확보해야 합니다 .

이제 List  또는  Map 과 마찬가지로 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  핵심 기능 에  대해 자세히 살펴보았습니다.

일부 BigCollections 를 가지고 놀기 전에  FastUtil 이 제공하는 유형별 컬렉션 중 일부 를 살펴 보았습니다 .

항상 그렇듯이 코드는 GitHub 에서 찾을 수 있습니다.

Generic footer banner