速度之王 — LZ4压缩算法与其他算法的比较
LZ4?(Extremely Fast Compression algorithm)
項目:http://code.google.com/p/lz4/
作者:Yann Collet
本文作者:zhangskd @ csdn blog
?
簡介
?
LZ4 is a very fast lossless compression algorithm, providing compression speed at 400MB/s per core,
scalable with multi-cores CPU. It also features an extremely fast decoder, with speed in multiple GB/s per core,
typically reaching RAM speed limits on multi-core systems.
A high compression derivative, called LZ4_HC, is also provided. It trades CPU time for compression ratio.
?
(1) 橫向對比
Quick comparison: single thread, Core i5-3340M @2.7GHz, using the Open-Source Benchmark by m^2 (v0.14.2)
compiled with GCC v4.6.1 on Linux Ubuntu 64-bits v11.10, using the Silesia Corpus.
對比當前流行的壓縮工具,可以看到LZ4具有最快的壓縮和解壓速度,盡管壓縮比一般。
?
?
QuickLZ官網:http://www.quicklz.com/
QuickLZ is the world's fastest compression library, reaching 308MB/s per core.
QuickLZ自稱是世界上最快的壓縮算法,然而我們看到它和LZ4還是有差距的,特別是解壓速度。
?
snappy項目:https://code.google.com/p/snappy/
snappy is developed by Google based on ideas from LZ77 and open-sourced in 2011.
It was designed to be very fast and stable, but not to achieve a high compression ratio.
Compression speed is 250MB/s and decompression speed is 500MB/s using a single threaded,
64-bit core i7 processor. The compression ratio is 20-100% lower than gzip.
snappy追求的是速度,壓縮比并不高。
?
(2) 縱向對比
LZ4能很好的支持多線程環境,獲得更高的壓縮和解壓速度。
?
(3) 技術背景
多媒體技術 -> 無損壓縮 -> 詞典編碼 -> LZ77算法 -> LZ4
詞典編碼(Dictionary Encoding),根據的是數據本身包含有重復代碼序列這個特性。
主要分為兩類:
1. 查找正在壓縮的字符序列是否在前面輸入數據中出現過,如果是,則用指向早期出現過的字符串的“指針”替代
????重復的字符串。這里的“詞典”是指以前處理過的數據。(LZ77、LZSS)。
2. 從輸入的數據中創建一個“短語詞典”,編碼數據過程中當遇到已經在詞典中出現過的“短語”時,編碼器就輸
????出這個詞典中的短語的“索引號”,而不是短語本身。(LZ78、LZW)
?
(4) 其它格式
以下是一些常用的壓縮格式。
1. zip
????zlib庫,可通過包含zlib.h使用。
????zip原名為Deflate,僅支持一個LZ77的變種算法Deflate。
????zip/unzip,后綴為.zip。zip也是Windows下常見的壓縮格式。
2. gzip
????gzip/gunzip是GNU程序,后綴為.gz。Web也常用GZIP壓縮技術。
????首先使用LZ77算法進行壓縮,對結果再使用huffman編碼進行壓縮。
????tar中用-z來調用:
?????????tar -czf pic.tar.gz *.jpg
?????????tar -xzf pic.tar.gz
3. bzip2
????bzip2/bunzip2,后綴為.bz2。
????相比于gzip,壓縮比更高,壓縮效果比傳統的LZ77/LZ78更好,但壓縮速度較慢。
????首先使用Burrows-Wheeler變換(BWT,塊排序文本壓縮),然后使用哈夫曼編碼進行壓縮。
????tar中使用-j來調用:
????????tar -cjf pic.tar.bz2 *.jpg
????????tar -xjf pic.tar.bz2
4. compress
????compress/uncompress,后綴為.Z,現在已經不再流行了。
????使用LZ78算法的變種LZW。
????tar中使用-Z來調用。
6. rar
????rar/unrar,后綴為.rar。
????rar格式較zip格式的壓縮比高。
????注意RAR非免費,是Windows下常見壓縮格式,也有RAR for Linux。
????????rar a pic *.jpg // pic.rar
????????rar?e pic.rar // pic
7. 7z
????7-Zip,后綴為.7z。
????和rar、zip一樣,7z也是Windows下常見的壓縮格式。
????使用改良與優化后的LZ77算法LZMA、LZMA2,壓縮比高于zip。
8. xz
????xz,后綴為.xz。
????如果說LZ4是壓縮速度之王,xz則是壓縮比之王。
????一般來說,用xz壓縮后的文件,能比用gzip壓縮的小30%,比用bzip2壓縮的小15%。
????主要使用LZMA2壓縮算法。
????tar不支持xz格式,xz / xz -d。
?
LZ77
?
我們看到很多壓縮格式都是基于LZ77的,所以先來了解下LZ77算法,這里引用了較多的網上資料:)
1977年,Jacob Ziv和Abraham Lempel描述了一種基于滑動窗口緩存的技術,該緩存用于保存最近剛剛處理的文本。
LZ77編碼的核心是查找從前向緩沖器開始的最長的匹配串。
?
壓縮算法使用了兩個緩存:
1. 滑動歷史緩存,包含了前面處理過的N個源字符。
2. 前向緩存,包含了將要處理的下面L個字符。
?
壓縮過程
算法嘗試將前向緩存開始的兩個或多個字符與滑動歷史緩存中的字符串相匹配。
如果沒有發現匹配,前向緩存的第一個字符作為9bit的字符輸出并且移入滑動窗口,滑動窗口中最久的字符被移除。
如果找到匹配,算法繼續掃描以找到最長的匹配。然后匹配字符串作為三元組輸出(選項、指針和長度)。對于K個字符
的字符串,滑動窗口中最久的K個字符被移出,并且被編碼的K個字符被移入窗口。
?
更具體來說:
1. 從當前壓縮位置開始,查看未編碼的數據,并試圖在滑動窗口中找出最長的匹配字符串,如果找到,則進行步驟2,否則進行步驟3。
2. 輸出三元符號組(off, len, c)。其中off為窗口中匹配字符串相對窗口邊界的偏移,len為可匹配的長度,c為下一個字符。
????然后將窗口向后滑動len + 1個字符,繼續步驟1。
3. 輸出三元符合組(0, 0, c)。其中c為下一個字符。然后將窗口向后滑動len + 1個字符,繼續步驟1。
?
實例
假設窗口大小為10個字符,我們剛編碼過的字符(滑動窗口)是:abcdbbccaa,即將編碼的字符(前向緩存)是:abaeaaabaee。
1. 和編碼字符匹配的最長串為ab,下一個字符為a,輸出三元組(0, 2, a)。
????窗口向后滑動3個字符為:dbbccaaaba,前向緩存為:eaaabaee。
2. 字符e在窗口中無匹配,輸出三元組(0, 0, e),窗口向后滑動1個字符為:bbccaaabae,前向緩存為:aaabaee。
3. 前向緩存的最長匹配串為aaabae,下一個字符為e,輸出三元組(4, 6, e),完成編碼。
?
解壓過程
解壓算法必須保存解壓輸出的最后N個字符(滑動窗口)。
當碰到編碼字符串時,使用指針和長度字段,將編碼替換成實際的正文字符串。
?
評價
算法使用了有限的窗口在以前的文本中查找匹配,對于相對于窗口大小來說非常長的文本塊,很多可能的匹配就會被丟掉。
窗口大小可以增加,但這會帶來兩個損失:
1. 算法的處理時間會增加,因為它必須為滑動窗口的每個位置進行一次與前向緩存的字符串匹配的工作。
2. 指針字段必須更長,以允許更長的跳轉。
?
在多數情況下,lz77擁有較高的壓縮效率。而在待壓縮文件中絕大多數是些超長匹配,并且相同的超長匹配高頻率地反復
出現時,lzw更具優勢。GIF就是采用了lzw算法來壓縮背景單一、圖形簡單的圖片。zip是用來壓縮通用文件的,這就是它
采用對大多數文件有更高壓縮率的lz77算法的原因。
?
優化
精心設計三元組(off, len, c)中每個分量的表示方法,才能達到較好的效果。
(1) off
off為窗口內的偏移,通常的經驗是,偏移接近窗口尾部的情況要多于接近窗口頭部的情況,這是因為字符串在與其接近的
位置容易找到匹配串,但對于普通的窗口大小(如4096字節)來說,偏移值基本還是均勻分布的,我們完全可以用固定的位
數來表示它。
(2) len
len為字符串長度,它在大多數時候不會太大,少數情況下才會發生大字符串的匹配。顯然可以使用一種變長編碼方式來表
示該長度值。要輸出變長的編碼,該編碼必須滿足前綴碼的條件。Huffman編碼可以用于此處,但不是最好的選擇。
Golomb編碼應用比較廣泛,對于較小的數用較短的編碼,對較大的數用較大的編碼表示。
(3) c
c為前向緩存中的不匹配字符。直接用8個二進制位編碼。
(4) 輸出格式
LZ77的原始算法采用三元組輸出每一個匹配串及其后續字符,即使沒有匹配,仍需要輸出一個len=0的三元組來表示單個字符。
實驗表明,這種方式對于某些特殊情況(例如同一字符不斷重復的情形)有著較好的適應能力。
對一般數據,有一種更有效的輸出方式。
將每一個輸出分成匹配串和單個字符兩種類型,并首先輸出一個二進制位對其加以區分。例如,輸出0表示下面是一個匹配串,
輸出1表示下面是一個單個字符。之后,如果要輸出的是單個字符,我們直接輸出該字符的字節值,需要8個二進制位。
也就是說,輸出一個單個的字符共需要9個二進制位。
如果要輸出的是匹配串,則輸出off和len。off可以用定長編碼,也可以用變長前綴碼。len用變長前綴碼。有時候我們可以對匹配
長度加以限制,例如,限制最少匹配3個字符。因為對于2個字符的匹配串,我們使用匹配串的輸出方式不一定比我們直接輸出2
個單個字符(共需18位)節省空間。
這種輸出方式的優點是:輸出單個字符的時候比較節省空間。另外,因為不強求每次都外帶一個后續字符,可以適應一些較長
匹配的情況。
(5) 查找匹配串
在滑動窗口中查找最長的匹配串,是LZ77算法中的核心問題,關系著空間和時間復雜度。
?
golomb
?
哥倫布編碼。主要針對整數進行編碼,對較小的數用較短的編碼,對較大的數用較大的編碼表示。
假設x為要進行編碼的整數,當x趨于較小的取值時候,此時的Golomb編碼較短,可以有效的節省空間。
?
壓縮算法:
1. 選定參數m,b = 2^m,注意m是要在壓縮前指定的。
2. q = <int> ((x - 1) / b),<int>表示取整。
3. r = x - qb - 1,所以x = qb + r + 1。(注意這個1不用存儲,只要默認恢復出來的數據加1即可)
4. 這樣要編碼的x由兩部分組成:
????a. 第一部分由q個1加上一個0組成,表示q。
????b. 第二部分由m個位組成,表示r。
?
恢復算法:
如果讀入1,則繼續往后讀,直到讀入0,此時讀入的1的個數就是q。
之后的m位(m事先約定了)為r。
所以可以計算出x = qb + 1 + r = q * 2^m + r + 1。
?
Reference
?
[1]. http://fastcompression.blogspot.com/p/lz4.html
[2]. http://jpkc.zust.edu.cn/2007/dmt/course/MMT03_05_1.htm
[3]. http://jpkc.zust.edu.cn/2007/dmt/course/MMT03_05_2.htm
[4]. http://hi.baidu.com/guoliqiang2006/item/127c8f989b494b4ef14215db
[5]. http://blog.chinaunix.net/uid-17240700-id-3347894.html
[6]. http://jpkc.zust.edu.cn/2007/dmt/course/Mmt03_02_2.htm
[7]. http://tukaani.org/xz/
?
總結
以上是生活随笔為你收集整理的速度之王 — LZ4压缩算法与其他算法的比较的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 伍德里奇计量经济学第六版第七章计算机答案
- 下一篇: 程序结束后去哪儿了?