經由過程Java測試幾種緊縮算法的機能(附測試代碼下載)。本站提示廣大學習愛好者:(經由過程Java測試幾種緊縮算法的機能(附測試代碼下載))文章只能為提供參考,不一定能成為您想要的結果。以下是經由過程Java測試幾種緊縮算法的機能(附測試代碼下載)正文
本文將會對經常使用的幾個緊縮算法的機能作一下比擬。成果注解,某些算法在極端刻薄的CPU限制下仍能正常任務。
文中停止比擬的算有:
JDK GZIP ——這是一個緊縮比高的慢速算法,緊縮後的數據合適歷久應用。JDK中的java.util.zip.GZIPInputStream / GZIPOutputStream就是這個算法的完成。
JDK deflate ——這是JDK中的又一個算法(zip文件用的就是這一算法)。它與gzip的分歧的地方在於,你可以指定算法的緊縮級別,如許你可以在緊縮時光和輸入文件年夜小長進行均衡。可選的級別有0(不緊縮),和1(疾速緊縮)到9(慢速緊縮)。它的完成是java.util.zip.DeflaterOutputStream / InflaterInputStream。
LZ4緊縮算法的Java完成——這是本文引見的算法中緊縮速度最快的一個,與最疾速的deflate比擬,它的緊縮的成果要稍微差一點。
Snappy——這是Google開辟的一個異常風行的緊縮算法,它旨在供給速度與緊縮比都絕對較優的緊縮算法。
緊縮測試
要找出哪些既合適停止數據緊縮測試又存在於年夜多半Java開辟人員的電腦中(我可不願望你為了運轉這個測試還得個幾百兆的文件)的文件也實在費了我很多功夫。最初我想到,年夜多半人應當都邑在當地裝置有JDK的文檔。是以我決議將javadoc的目次全部歸並成一個文件——拼接一切文件。這個經由過程tar敕令可以很輕易完成,但並不是一切人都是Linux用戶,是以我寫了個法式來生成這個文件:
public class InputGenerator { private static final String JAVADOC_PATH = "your_path_to_JDK/docs"; public static final File FILE_PATH = new File( "your_output_file_path" ); static { try { if ( !FILE_PATH.exists() ) makeJavadocFile(); } catch (IOException e) { e.printStackTrace(); } } private static void makeJavadocFile() throws IOException { try( OutputStream os = new BufferedOutputStream( new FileOutputStream( FILE_PATH ), 65536 ) ) { appendDir(os, new File( JAVADOC_PATH )); } System.out.println( "Javadoc file created" ); } private static void appendDir( final OutputStream os, final File root ) throws IOException { for ( File f : root.listFiles() ) { if ( f.isDirectory() ) appendDir( 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 underlyingStream ) throws IOException; } public int baseBenchmark( final StreamFactory factory ) throws IOException { try ( ByteArrayOutputStream bos = new ByteArrayOutputStream((int) m_inputFile.toFile().length()); OutputStream os = factory.getStream( bos ) ) { Files.copy(m_inputFile, os); os.flush(); return bos.size(); } } }
這些測試用例都異常類似(在文末有它們的源代碼),這裡只列出了個中的一個例子——JDK deflate的測試類;
public class JdkDeflateTest extends TestParent { @Param({"1", "2", "3", "4", "5", "6", "7", "8", "9"}) public int m_lvl; @Benchmark public int deflate() throws IOException { return baseBenchmark(new StreamFactory() { @Override public OutputStream getStream(OutputStream underlyingStream) throws IOException { final Deflater deflater = new Deflater( m_lvl, true ); return new DeflaterOutputStream( underlyingStream, deflater, 512 ); } }); } }
測試成果
輸入文件的年夜小
起首我們來看下輸入文件的年夜小:
||完成||文件年夜小(字節)|| ||GZIP||64,200,201|| ||Snappy (normal)||138,250,196|| ||Snappy (framed)|| 101,470,113|| ||LZ4 (fast)|| 98,316,501|| ||LZ4 (high) ||82,076,909|| ||Deflate (lvl=1) ||78,369,711|| ||Deflate (lvl=2) ||75,261,711|| ||Deflate (lvl=3) ||73,240,781|| ||Deflate (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|| ||Deflate (lvl=9) ||63,839,200||
可以看出文件的年夜小相差差異(從60Mb到131Mb)。我們再來看下分歧的緊縮辦法須要的時光是若干。
緊縮時光
||完成||緊縮時光(ms)|| ||Snappy.framedOutput ||2264.700|| ||Snappy.normalOutput ||2201.120|| ||Lz4.testFastNative ||1056.326|| ||Lz4.testFastUnsafe ||1346.835|| ||Lz4.testFastSafe ||1917.929|| ||Lz4.testHighNative ||7489.958|| ||Lz4.testHighUnsafe ||10306.973|| ||Lz4.testHighSafe ||14413.622|| ||deflate (lvl=1) ||4522.644|| ||deflate (lvl=2) ||4726.477|| ||deflate (lvl=3) ||5081.934|| ||deflate (lvl=4) ||6739.450|| ||deflate (lvl=5) ||7896.572|| ||deflate (lvl=6) ||9783.701|| ||deflate (lvl=7) ||10731.761|| ||deflate (lvl=8) ||14760.361|| ||deflate (lvl=9) ||14878.364|| ||GZIP ||10351.887||
我們再將緊縮時光和文件年夜小歸並到一個表中來統計下算法的吞吐量,看看能得出甚麼結論。
吞吐量及效力
||完成||時光(ms)||未緊縮文件年夜小||吞吐量(Mb/秒)||緊縮後文件年夜小(Mb)|| ||Snappy.normalOutput ||2201.12 ||338 ||153.5581885586 ||131.8454742432|| ||Snappy.framedOutput ||2264.7 ||338 ||149.2471409017 ||96.7693328857|| ||Lz4.testFastNative ||1056.326 ||338 ||319.9769768045 ||93.7557220459|| ||Lz4.testFastSafe ||1917.929 ||338 ||176.2317583185 ||93.7557220459|| ||Lz4.testFastUnsafe ||1346.835 ||338 ||250.9587291688 ||93.7557220459|| ||Lz4.testHighNative ||7489.958 ||338 ||45.1270888301 ||78.2680511475|| ||Lz4.testHighSafe ||14413.622 ||338 ||23.4500391366 ||78.2680511475|| ||Lz4.testHighUnsafe ||10306.973 ||338 ||32.7933332124 ||78.2680511475|| ||deflate (lvl=1) ||4522.644 ||338 ||74.7350443679 ||74.7394561768|| ||deflate (lvl=2) ||4726.477 ||338 ||71.5120374012 ||71.7735290527|| ||deflate (lvl=3) ||5081.934 ||338 ||66.5101120951 ||69.8471069336|| ||deflate (lvl=4) ||6739.45 ||338 ||50.1524605124 ||64.9452209473|| ||deflate (lvl=5) ||7896.572 ||338 ||42.8033835442 ||62.6564025879|| ||deflate (lvl=6) ||9783.701 ||338 ||34.5472536415 ||61.2258911133|| ||deflate (lvl=7) ||10731.761 ||338 ||31.4952969974 ||61.0446929932|| ||deflate (lvl=8) ||14760.361 ||338 ||22.8991689295 ||60.8825683594|| ||deflate (lvl=9) ||14878.364 ||338 ||22.7175514727 ||60.8730316162|| ||GZIP ||10351.887 ||338 ||32.651051929 ||61.2258911133||
可以看到,個中年夜多半完成的效力長短常低的:在Xeon E5-2650處置器上,高等其余deflate年夜約是23Mb/秒,即便是GZIP也就只要33Mb/秒,這年夜概很難使人滿足。同時,最快的defalte算法年夜概能到75Mb/秒,Snappy是150Mb/秒,而LZ4(疾速,JNI完成)能到達難以相信的320Mb/秒!
從表中可以清楚地看出今朝有兩種完成比擬處於優勢:Snappy要慢於LZ4(疾速緊縮),而且緊縮後的文件要更年夜。相反,LZ4(高緊縮比)要慢於級別1到4的deflate,而輸入文件的年夜小即使和級別1的deflate比擬也要年夜上很多。
是以假如須要停止“及時緊縮”的話我確定會在LZ4(疾速)的JNI完成或許是級別1的deflate中停止選擇。固然假如你的公司不許可應用第三方庫的話你也只能應用deflate了。你還要綜合斟酌有若干余暇的CPU資本和緊縮後的數據要存儲到哪裡。比喻說,假如你要將緊縮後的數據存儲到HDD的話,那末上述100Mb/秒的機能對你而言是毫無贊助的(假定你的文件足夠年夜的話)——HDD的速度會成為瓶頸。異樣的文件假如輸入到SSD硬盤的話——即使是LZ4在它眼前也顯得太慢了。假如你是要先緊縮數據再發送到收集上的話,最好選擇LZ4,由於deflate75Mb/秒的緊縮機能跟收集125Mb/秒的吞吐量比擬真是小巫見年夜巫了(固然,我曉得收集流量還有包頭,不外即便算上了它這個差距也是相當可不雅的)。
總結
假如你以為數據緊縮異常慢的話,可以斟酌下LZ4(疾速)完成,它停止文本緊縮能到達年夜約320Mb/秒的速度——如許的緊縮速度對年夜多半運用而言應當都感知不到。
假如你受限於沒法應用第三方庫或許只願望有一個略微好一點的緊縮計劃的話,可以斟酌下應用JDK deflate(lvl=1)停止編解碼——異樣的文件它的緊縮速度能到達75Mb/秒。
源代碼
Java緊縮測試源碼