이 기사는 일반적으로 사용되는 여러 압축 알고리즘의 성능을 비교합니다. 결과는 일부 알고리즘이 여전히 까다로운 CPU 제약 조건에서 제대로 작동한다는 것을 보여줍니다.
이 기사의 비교에는 다음이 포함됩니다.
JDK GZIP- 압축 비율이 높은 느린 알고리즘이며 압축 데이터는 장기 사용에 적합합니다. java.util.zip.gzipinputstream / gzipoutputstream in JDK는이 알고리즘의 구현입니다.
JDK DEFLATE- JDK의 또 다른 알고리즘입니다 (이 알고리즘은 ZIP 파일에 사용됩니다). GZIP와는 다른 점은 압축 시간과 출력 파일 크기의 균형을 맞출 수 있도록 알고리즘의 압축 수준을 지정할 수 있다는 것입니다. 선택적 레벨은 0 (압축되지 않음), 1 (빠른 압축)에서 9 (느린 압축)입니다. 구현은 java.util.zip.deflateroutputstream/lainpatinputstream입니다.
LZ4 압축 알고리즘의 Java 구현 -이 기사에서 소개 된 알고리즘 중 가장 빠른 압축 속도입니다. 가장 빠른 디 플레이트와 비교할 때 압축 결과는 약간 더 나쁩니다.
Snappy- 이것은 Google에서 개발 한 매우 인기있는 압축 알고리즘입니다. 압축 알고리즘을 비교적 우수한 속도와 압축 비율로 제공하는 것을 목표로합니다.
압축 테스트
또한 데이터 압축 테스트에 적합한 파일을 찾는 데 많은 시간이 걸렸으며 대부분의 Java 개발자 컴퓨터에 존재합니다 (이 테스트를 실행하기 위해 수백 메가 바이트의 파일을 갖기를 원하지 않습니다). 마지막으로, 대부분의 사람들은 JDK에 대한 문서를 현지에서 설치해야한다고 생각했습니다. 따라서 전체 Javadoc 디렉토리를 하나의 파일로 병합하여 모든 파일을 접합하기로 결정했습니다. 이것은 TAR 명령으로 쉽게 수행 할 수 있지만 모든 사람이 Linux 사용자 인 것은 아니므 로이 파일을 생성하는 프로그램을 작성했습니다.
공개 클래스 inputGenerator {private static final String javadoc_path = "your_path_to_jdk/docs"; 공개 정적 최종 파일 file_path = 새 파일 ( "your_output_file_path"); static {try {if (! file_path.exists ()) makejavadocfile (); } catch (ioexception e) {e.printstacktrace (); }} private static void makejavadocfile ()는 ioexception {try (outputStream os = new bufferedOutputStream (new FileOutputStream (file_path), 65536)) {부록 (OS, 새 파일 (javadoc_path)); } system.out.println ( "Javadoc 파일 생성"); } private static void 부록 (Final OutputStream OS, 최종 파일 루트)은 ioException {for (file f : root.listfiles ()) {if (f.isdirectory ()) 부록 (os, f); else files.copy (f.topath (), os); }}}내 컴퓨터의 전체 파일의 크기는 354,509,602 바이트 (338MB)입니다.
시험
처음에는 전체 파일을 메모리로 읽은 다음 압축하고 싶었습니다. 그러나 결과는 4G 기계조차도 힙 메모리 공간이 쉽게 떨어질 수 있음을 보여줍니다.
그래서 운영 체제의 파일 캐시를 사용하기로 결정했습니다. 여기서 사용하는 테스트 프레임 워크는 JMH입니다. 이 파일은 워밍업 단계에서 운영 체제에 의해 캐시에로드됩니다 (워밍업 단계에서 두 번 압축). 컨텐츠를 BytearRayoutputStream 스트림으로 압축하겠습니다 (이것이 가장 빠른 방법은 아니지만 각 테스트마다 비교적 안정적이며 압축 데이터를 디스크에 작성하는 데 시간이 걸리지 않으므로이 출력을 저장하는 데 일부 메모리 공간이 필요합니다.
아래는 테스트 클래스의 기본 클래스입니다. 모든 테스트는 압축 출력 스트림의 다른 구현에서만 다르 므로이 테스트 기본 클래스를 재사용하고 StreamFactory 구현에서 스트림을 생성 할 수 있습니다.
@outputtimeUnit (timeUnit.milliseconds) @state (scope.thread) @fork (1) @warmup (iterations = 2) @measurement (iterations = 3) @benchmarkmode (mode.singleshottime) public class testparent {Protected Path m_inputfile; @setup public void setup () {m_inputfile = inputgenerator.file_path.topath (); } interface streamFactory {public outputStream getStream (Final OutputStream inderyingStream)은 ioException을 던집니다. } public int basebenchmark (Final StreamFactory Factory)는 ioException을 던지 었습니다. {try (bytearrayoutputstream bos = new ByTearRayoutputStream ((int) m_inputfile.tofile ()) os.flush (); return bos.size (); }}}이 테스트 사례는 매우 유사합니다 (소스 코드는 기사 끝에서 사용할 수 있습니다). 하나의 예제 만 여기에 나열되어 있습니다. JDK DEFLATE의 테스트 클래스;
공개 클래스 jdkdeflateTest는 testparent {@param ({ "1", "2", "3", "4", "5", "6", "7", "8", "9"})를 확장합니다. public int m_lvl; @benchmark public int deflate ()는 ioexception {return basebenchmark (new streamFactory () {@override public outputStream getStream (outputStream indryingstream) IoException {최종 Deflater Deflater = New Deflater (M_LVL, TRUE); return New DeflatePutStream (Deflatertream, 512); }}테스트 결과
출력 파일의 크기
먼저 출력 파일의 크기를 살펴 보겠습니다.
|| 구현 || 파일 크기 (바이트) |||| gzip || 64,200,201 |||| snappy (정상) || 138,250,| snappy (프레임) || 101,470,113 ||||| lz4 (빠른) || 98,316,501 |||| lz4 (High) || 82,076,909 ||| deflate (lvl = 1) || 78,369,711 ||| | deflate (lvl = 2) || 75,261,711 ||||| | deflate (lvl = 3) || 781 ||||||||||||||||||||||| || | (LVL = 4) || 68,090,059 || || deflate (lvl = 5) || 65,699,810 |||| | deflate (lvl = 6) || 64,200,191 ||||| | deflate (lvl = 7) || 64,013,638 |||| deflate (lvl = 8) || 63,845,758 | || 63,839,200 |||
파일 크기는 크게 다르다는 것을 알 수 있습니다 (60MB에서 131MB). 다른 압축 방법에 걸리는 시간을 살펴 보겠습니다.
압축 시간
|| 구현 || 압축 시간 (ms) |||| snappy.framedoutput || 2264.700 |||| snappy.normaloutput || 2201.120 |||| lz4.testnative || 1056.326 |||| lz4.testfastunsa fe || 1346.835 |||| lz4.testfastsafe || 1917.929 |||| lz4.testhighnative || 7489.958 |||| lz4.testhighunsafe || 10306.973 |||||| | | | | | || 14413.622 |||| deflate (lvl = 1) || 4522.644 |||| deflate (lvl = 2) || 4726.477 |||| deflate (lvl = 3) || 5081.934 |||| | deflate (lvl = 4) || 450 | || 7896.572 |||| deflate (lvl = 6) || 9783.701 |||| deflate (lvl = 7) || 10731.761 |||| deflate (lvl = 8) || 14760.361 |||| | deflate (lvl = 9) | || 10351.887 ||
그런 다음 압축 시간과 파일 크기를 테이블에 병합하여 알고리즘의 처리량을 계산하고 어떤 결론을 도출 할 수 있는지 확인합니다.
처리량과 효율성
|| 구현 || 시간 (ms) || 압축되지 않은 파일 크기 || 처리량 (mb/sec) ||| 압축 파일 크기 (MB) |||| snappy.normaloutput || 2201.12 || 338 || 153.558188885586 || 131.8454742432 ||| | || 22264. || 149.2471409017 || 96.7693328857 |||| lz4.testfastnative || 1056.326 || 338 || 319.9769768045 || 93.7557220459 ||||||||||||||| | | | | 1917.929 || 338 || 176.2317583185 || 93.7557220459 ||||| lz4.testfastunsafe || 1346.835 || 338 || 250.9587291688 || 93.7557220459 ||||| lz4.Teshighnative | || 45.1270888301 || 78.2680511475 |||| lz4.testhighsafe || 14413.622 || 338 || 23.4500391366 || 78.2680511475 |||||||||||||||| | | | | | 338 || 32.7933332124 || 78.2680511475 |||| deflate (lvl = 1) || 4522.644 || 338 || 74.7350443679 || 74.7394561768 ||| | deflate (lvl = 2) | || 71.5120374012 || 71.7735290527 |||| deflate (lvl = 3) || 5081.934 || 338 || 66.5101120951 || 69.8471069336 ||| | deflate (lvl = 4) | || 50.1524605124 || 64.9452209473 |||| deflate (lvl = 5) || 7896.572 || 338 || 42.8033835442 || 62.6564025879 ||| deflate (lvl = 6) | || 34.5472536415 || 61.2258911133 ||||| deflate (lvl = 7) || 10731.761 || 338 || 31.4952969974 || 61.0446929932 |||||| 7) || 14760.361 || 22.8991689295 || 60.8825683594 |||| deflate (lvl = 9) || 14878.364 || 338 || 22.7175514727 || 60.8730316162 ||| gzip || 10351.| 32.41051051051051051051051051051051051051. || 61.2258911133 ||
알 수 있듯이 대부분의 구현은 매우 비효율적입니다. Xeon E5-2650 프로세서에서는 높은 수준의 디플레이트는 약 23MB/sec이며 GZIP조차도 33MB/sec이므로 만족하기가 어려울 수 있습니다. 동시에, 가장 빠른 훼손 알고리즘은 약 75MB/sec, Snappy는 150MB/sec이며 LZ4 (FAST, JNI 구현)는 놀라운 320MB/sec에 도달 할 수 있습니다!
테이블에서 현재 단점이있는 두 가지 구현이 있음을 명확하게 볼 수 있습니다. Snappy는 LZ4 (빠른 압축)보다 느리고 압축 파일이 더 큽니다. 반대로 LZ4 (높은 압축 비율)는 레벨 1에서 4 레벨에서 디 플레이트보다 느리게 느리고 출력 파일의 크기는 레벨 1에서 Deflate의 크기보다 훨씬 큽니다.
따라서 "실시간 압축"을 수행 해야하는 경우 LZ4 (FAST) JNI 구현 또는 레벨 1 디플레이트에서 확실히 선택합니다. 물론 회사에서 타사 라이브러리를 허용하지 않으면 Deflate 만 사용할 수 있습니다. 또한 얼마나 많은 무료 CPU 자원의 수와 압축 데이터가 저장되는 위치를 종합적으로 고려해야합니다. 예를 들어, 압축 데이터를 HDD에 저장하려면 위의 100MB/s 성능이 도움이되지 않습니다 (파일이 충분히 크다고 가정). HDD의 속도는 병목 현상이됩니다. 동일한 파일이 SSD 하드 드라이브에 출력되면 LZ4조차도 너무 느리게 나타납니다. 먼저 데이터를 압축 한 다음 네트워크로 보내려면 LZ4를 선택하는 것이 가장 좋습니다. Deflate75MB/s의 압축 성능은 125MB/s의 처리량에 비해 실제로 작기 때문에 (물론, 네트워크 트래픽에 Baotou가 있음을 알고 있습니다.
요약
데이터 압축이 매우 느리다고 생각되면 LZ4 (FAST) 구현을 고려할 수 있습니다.이 구현은 약 320MB/sec의 텍스트 압축 속도를 달성 할 수 있습니다. 이러한 압축 속도는 대부분의 응용 분야에서 인식되어서는 안됩니다.
타사 라이브러리를 사용할 수 없거나 약간 더 나은 압축 솔루션을 원한다면 인코딩 및 디코딩에 JDK Deflate (LVL = 1)를 사용하는 것을 고려할 수 있습니다. 동일한 파일이 동일한 파일을 75MB/s로 압축 할 수 있습니다.
소스 코드
Java 압축 테스트 소스 코드