zlib库介绍四:zlib算法(LZ77、LZ78、霍夫曼编码、滑动窗口、Rabin-Karp算法、哈希链、I/O缓冲区)
1.簡介
在2017年,我有機會從事一個旨在提高數據壓縮性能的項目。在此過程中,我研究了zlib庫及其實現的deflate壓縮算法。在這里,我想與那些也希望對zlib有更好理解的人分享我的研究。
1.1 什么是zlib
zlib是一個免費的開源軟件庫,用于無損數據壓縮?和?減壓。它是由Jean-loup Gailly(壓縮)和Mark Adler(解壓縮)用C語言編寫的。zlib的第一個版本于1995年5月發(fā)布。Jean-loupGailly和Mark Adler也為gzip(GNU zip)。在后臺,gzip使用zlib庫。
迄今為止,zlib主要由Mark Adler維護,其最新更新和版本均可在GitHub上找到。Mark Adler還積極參與Stack Overflow,以回答有關zlib和gzip的技術問題。
許多軟件應用程序和庫都使用zlib。如果引起注意,您幾乎可以在操作系統,Internet服務,流服務,文檔編輯器等中的任何地方找到zlib。這是這些應用程序的不完整列表。
zlib規(guī)范于1996年5月獲得正式的Internet RFC(征求意見)狀態(tài)。
- RFC 1950:zlib壓縮數據格式
- RFC 1951:壓縮壓縮數據格式
- RFC 1952:gzip文件格式
2.壓縮算法
的?壓縮?zlib中使用的算法是?放氣方法。deflate方法將輸入數據編碼為壓縮數據。的減壓?zlib中使用的算法是?膨脹?方法,這是一種解碼過程,需要使用壓縮的位流進行解壓縮并正確生成原始的全尺寸數據或文件。
在本文檔中,我將重點介紹zlib的壓縮部分以及zlib對zlib的實現。?放氣算法。
我會用這樣的話?“數據字節(jié)”,?“數據字節(jié)”,?“數據符號”,?“數據流”,?“位流”指示要壓縮的數據。在下面的部分中,這些詞具有相同的含義并且可以互換。
2.1 放氣
放氣的方法最初是由定義菲爾·卡茨在PKWARE的歸檔工具PKZIP 2.x版本?它是LZ77算法?和?霍夫曼編碼。
下圖從高層次說明了放氣和充氣過程。
2.2 LZ77
LZ77是基于字典的無損壓縮算法。它也被稱為LZ1。
基于字典的算法的基本思想是,通過引用該序列的先前出現來替換數據中特定字節(jié)序列的出現。
基于字典的壓縮算法有兩種主要類型:LZ77和LZ78。這兩個算法以兩個創(chuàng)建者Jakob Ziv和Abraham Lempel命名。LZ77(Lempel-Ziv77)和LZ78(Lempel-Ziv78)分別發(fā)表于1977年和1978年。
LZ77壓縮算法通過使用?滑動窗口?查找重復的數據序列,并使用稱為a的一對數字對每個重復的序列進行編碼?長距離對。
2.2.1 滑動窗口
滑動窗口用于檢查輸入數據序列,并維護用作字典的歷史數據。換句話說,字典是先前出現和編碼的數據的一部分。
滑動窗由兩部分組成:?搜索緩沖區(qū)和?前瞻緩沖區(qū)。搜索緩沖區(qū)包含字典-最近編碼的數據,而前瞻緩沖區(qū)包含要編碼的輸入數據序列的下一部分。下圖給出了一個滑動窗口的示例。
滑動窗的尺寸是影響壓縮性能的關鍵因素之一。如果滑動窗口太小,則壓縮器可能會發(fā)現較少的重復數據序列,結果,壓縮文件的大小將更大。如果滑動窗口太大,則壓縮器可能需要花費更長的時間來查找重復的數據序列,因此壓縮速度將變慢。
實際上,滑動窗口的大小通常可以從幾KB到MB,例如4 KB,32 KB,1 MB或4 MB。
2.2.2 長距離對
長度-距離對指示下一個?長度?字符與字符完全相同?距離?原始數據流中后面的字符。
在LZ77算法中,壓縮器通過搜索緩沖區(qū)進行搜索,直到找到與超前緩沖區(qū)中的第一個字符匹配為止。搜索緩沖區(qū)中可能存在多個匹配項,并且壓縮程序將找到長度最長的一個匹配項。當。。。的時候最長的匹配?找到后,壓縮器將其編碼為三元組?(D,L,C)?哪里:
- D =搜索光標到超前緩沖區(qū)起點的距離
- L =最長匹配的長度
- C =超前緩沖區(qū)中最長匹配的下一個字符
在三元組中添加第三個元素C的原因是為了處理在搜索緩沖區(qū)中找不到匹配項的情況。在這種情況下,D和L的值均為0,并且C是當前預讀緩沖區(qū)中的第一個字符。
下圖顯示了LZ77如何找到最長匹配項并為給定字符串編碼重復字符“axrrmaxrbaxssr”的示例。
實際上,壓縮器可以根據自己的實現來優(yōu)化編碼輸出,并選擇除?(D,L,C)?三胞胎。
2.3 霍夫曼編碼
霍夫曼編碼是一種統計壓縮方法。它使用以下代碼編碼數據符號(例如字符)可變長度代碼,代碼長度基于相應符號的頻率。
霍夫曼編碼以及其他可變長度編碼方法具有兩個屬性:
霍夫曼編碼有兩個步驟:
霍夫曼碼可以是?固定(靜態(tài))?要么?動態(tài)。兩者都用deflate方法。
可以通過檢查大量數據集并找到典型的代碼長度來創(chuàng)建固定的霍夫曼代碼。使用固定霍夫曼編碼時,所有輸入數據符號均使用相同的編碼。
動態(tài)霍夫曼碼是通過將輸入數據分為多個塊,并為每個數據塊生成代碼來生成的。
3. zlib的實現
zlib的實現是實用且高效的。在過去的20年中,人們進行了許多嘗試來提高壓縮應用程序的性能,但是似乎我們只能通過使用除放氣(和放氣),采用并行處理或改進CPU級別指令以外的算法來獲得更好的性能。因此,zlib(在其GitHub存儲庫中指出)相當龐大而精致的壓縮庫。
在以下各節(jié)中,我們將介紹zlib用于實現deflate壓縮算法的一些詳細技術。
3.1 壓縮等級
zlib具有10個壓縮級別(0-9)。不同級別的壓縮性能不同壓縮率?和?速度。級別0表示不壓縮,zlib將輸出原始數據。1級是最快的,但壓縮率較低。級別9提供最高的壓縮率,但壓縮速度較慢。zlib使用的默認壓縮級別為6。
在引擎蓋下,壓縮級別會在放氣過程中更改放氣策略和參數。更多細節(jié)將在以下各節(jié)中討論。
3.2 滑動窗口
在zlib中,滑動窗口的默認大小為64KB。滑動窗分為兩部分,分別對應搜索緩沖區(qū)?和?前瞻緩沖區(qū),每個部分為32KB。輸入字節(jié)被讀入窗口的后半部分,然后移至前半部分以保持至少32KB的字典。該組織確保始終以塊大小(8KB)的倍數執(zhí)行IO。此外,在較舊的平臺MSDOS上64KB的限制非常有用。
以下代碼段顯示了如何初始化滑動窗口。宏MAX_WBITS確定滑動窗口的大小。它是可配置的,默認值為15,這將導致32KB的搜索緩沖區(qū)和64KB的滑動窗口。
define MAX_WBITS 15 /* 32K LZ77 window */s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1;s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));當超前緩沖區(qū)不足時,數據將被復制到滑動窗口中。此過程在函數內部實現fill_window。
local void fill_window(s)deflate_state *s; {... }3.3 尋找最長的匹配
zlib用于在搜索緩沖區(qū)中找到最長匹配項的技術很簡單,而且對于大多數輸入文件來說,它是最快的:使用字符串匹配算法查找可能的匹配項,然后嘗試所有可能的匹配項并選擇最長的匹配項。
小字符串的匹配算法的靈感來自?Rabin-Karp算法。該算法的關鍵特征是,在字符串字典中的插入非常簡單,因此速度很快,并且完全避免了刪除。插入在每個輸入字符處執(zhí)行,而字符串匹配僅在上一個匹配結束時執(zhí)行。因此,最好花更多時間進行匹配,以允許非常快速的字符串插入并避免刪除。當發(fā)現較小的匹配項時,將使用蠻力方法來查找較長的字符串。
因此,總而言之,找到最長匹配項的過程包括兩個主要部分:
3.3.1?匹配長度限制
zlib將MIN_MATCH和MAX_MATCH定義為最低?和?最大值?匹配搜索的長度。
#define MIN_MATCH 3 #define MAX_MATCH 258MIN_MATCH設置為3。最小匹配長度等于3的原因很明顯:小于3的匹配將無助于減小編碼數據的大小,因為編碼數據符號的長度將相同或更長。
除非您更改相關代碼(例如,多次調用UPDATE_HASH函數),否則無法更改MIN_MATCH值。
將MAX_MATCH設置為258這個數字是來自一個事實,即一個長的距離對,這是LZ77編碼的數據符號的輸出,可以在最258個字節(jié)代表。長度至少需要一位,距離至少需要一位,因此輸入兩位可以發(fā)出258個字節(jié)。
zlib中的MAX_MATCH值可以更改,但是更改可能會影響壓縮性能。同樣在zlib中,還有一些由condition控制的邏輯MAX_MATCH == 258。啟用這些代碼后,使用現代編譯器時,可以提高壓縮性能。
#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)/* This code assumes sizeof(unsigned short) == 2. Do not use* UNALIGNED_OK if your compiler uses a different size.*/if (*(ushf*)(match+best_len-1) != scan_end ||*(ushf*)match != scan_start) continue;...3.3.2 Rabin-Karp算法
Rabin-Karp算法是由Richard M. Karp和Michael O. Rabin創(chuàng)建的字符串搜索算法。它使用散列來查找文本中一組模式字符串中的任何一個。例如,給定文字“AABAACAADAABAABA”和圖案“AABA”,我們可以使用Rabin-Karp算法來找出模式在索引中的文本存在0,9,12。
以下偽代碼描述了Rabin-Karp算法的工作原理。
# p is a pattern, its length is m # t is text, its length is n # the algorithm searches for pattern p in text tCompute hash_p (for pattern p) Compute hash_t (for the first substring of t with m length) for i = 0 to n - m:if hash_p == hash_t:Match t[i . . . i+m-1] with p, if matched return 1else:Update hash_t for t[i+1 . . . i+m] using rolling hash End的?平均?和?最佳情況下的運行時間Rabin-Karp算法的O表示O(n + m),其中n是文本的長度,m是圖案的長度。但是它最壞的情況下時間是O(nm)。當模式和文本的所有字符與文本的所有子字符串的哈希值與模式的哈希值匹配時,會發(fā)生Rabin-Karp算法的最壞情況。例如text = “AAAAAAA”和pattern = “AAA”。
Rabin-Karp算法性能的關鍵是通過使用以下命令來有效計算文本的連續(xù)子字符串的哈希值:?滾動哈希技術。滾動哈希的好處是,它只需執(zhí)行恒定數量的操作即可計算前一個子字符串的下一個子字符串的哈希值,而不必重新哈希整個子字符串。
3.3.3 哈希鏈
如前所述,Rabin-Karp算法檢查子字符串的哈希值,以查找文本中的匹配項。為了在存儲最新數據符號的搜索緩沖區(qū)中找到匹配項,zlib使用了哈希鏈組織保留每3個字節(jié)(或由MIN_MATCH定義的其他值)的哈希值的記錄。
zlib中的此哈希鏈通過使用兩個數組來實現:prev[]和head[]。兩個數組都將位置存儲在滑動窗口中。該head[]數組存儲哈希鏈的頭部,該prev[]數組存儲并鏈接具有相同哈希索引的字符串的位置。下圖顯示了哈希鏈如何工作的示例。
在此示例中,HashValue函數及其結果僅是示例,并不準確。
prev[]的大小限制為滑動窗口的一半。因為prev[]維護的鏈接僅適用于搜索緩沖區(qū)中的數據,并且默認情況下僅最后32K字符串。在索引prev[]陣列是窗口索引模32K。
以下代碼段顯示了zlib如何實現哈希鏈組織。哈希大小隨memLevel為每個壓縮級別配置的參數而變化。
s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits;s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)#define INSERT_STRING(s, str, match_head) \(UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \s->head[s->ins_h] = (Pos)(str)) #endif#define CLEAR_HASH(s) \s->head[s->hash_size-1] = NIL; \zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));在中CLEAR_HASH,數組head[]被清除。數組prev[]是動態(tài)清除的,不是這里清除的。
3.3.4 自適應搜索限制
在哈希鏈中搜索最長匹配項時,zlib會限制?鏈長 以提高搜索效率。搜索限制是通過以下方式設置的:
搜索極限值在?配置表:
local const config configuration_table[10] = { /* good lazy nice max_chain_length */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */在上面的代碼片段中:
- 0-9是壓縮級別。
- good,lazy,nice是一個很好的匹配,水上匹配和一個漂亮的匹配的長度值。
- max_chain_length?是zlib搜索的最大鏈長。
3.4 霍夫曼編碼
Zib既實現?靜態(tài)(固定)霍夫曼編碼?和?動態(tài)霍夫曼編碼。對于LZ77編碼數據的每個塊,zlib使用靜態(tài)霍夫曼編碼和動態(tài)霍夫曼編碼來計算該塊中的位數,然后選擇方法?產生?較小的數量數據的。如果使用兩種方法使位數相等,則zlib選擇靜態(tài)霍夫曼編碼,因為解碼過程更快。
整個數據流可以包含靜態(tài)和動態(tài)霍夫曼編碼數據的混合。在每個塊的放氣流頭中發(fā)送霍夫曼碼。
總而言之,zlib中的霍夫曼編碼過程包括以下步驟:
3.5 I / O緩沖區(qū)
壓縮中的一個重要概念是?數據塊。 壓縮數據格式由塊組成,這些塊的頭取決于塊數據。因此,deflate的輸出一次到達一個塊,直到第一個塊完成之前,什么都沒有寫(zlib或gzip標頭除外)。考慮到數據塊在deflate過程中如何傳輸,zlib實現了幾個緩沖區(qū)?存儲數據塊并控制I / O性能。
3.5.1 輸入緩沖器
開始壓縮之前,zlib?積累數據?在一個?輸入緩沖區(qū),當輸入緩沖區(qū)已滿時開始壓縮。默認輸入緩沖區(qū)大小為8KB。
之所以具有輸入緩沖區(qū),是因為zlib不會生成任何輸出數據,直到在其中生成16K數據符號為止。?文字緩沖區(qū)(文字緩沖區(qū)的默認大小為16K,有關文字緩沖區(qū)的詳細信息,請參見下一部分)。因此,以非常短的數據長度開始壓縮沒有任何好處。使用輸入緩沖區(qū)可提高I / O效率。
可以使用gzbuffer功能更改默認的輸入緩沖區(qū)大小。
gzbuffer(file, size) {...state->want = size;... }3.5.2 文字緩沖
文字緩沖區(qū)存儲的數據符號由LZ77編碼。符號可以是編碼為文字的單個字節(jié),也可以是長度-距離對,它可以對前32K未壓縮數據中某處最多258個字節(jié)的副本進行編碼。默認的文字緩沖區(qū)大小為16K,因此未壓縮數據的累積范圍為16K至4MB(對于高度可壓縮的數據)。
一旦?文字緩沖區(qū)已滿,zlib決定為霍夫曼編碼構造哪種塊,然后執(zhí)行此操作,創(chuàng)建標頭,該標頭針對動態(tài)塊描述該塊中的霍夫曼代碼,然后為該塊創(chuàng)建編碼符號。或者,它會創(chuàng)建一個存儲塊或靜態(tài)塊,無論結果是最少的位數。只有這樣,壓縮數據才能用于輸出。
默認文字緩沖區(qū)大小由marco配置DEF_MEM_LEVEL。在zlib的代碼中,DEF_MEM_LEVEL = 8,所有壓縮級別都相同。因此,所有壓縮級別都具有相同的16K文字緩沖區(qū)大小。
3.5.3 輸出緩沖器
為了輸出壓縮數據,zlib使用兩個緩沖區(qū):?暫掛緩沖區(qū), 和?輸出緩沖區(qū)。數據流如下圖所示:
初始化后,zlib將創(chuàng)建一個暫掛緩沖區(qū)(默認大小為36K)和一個輸出緩沖區(qū)(默認大小為8K)。首先輸出數據累積在未決緩沖區(qū)中,然后得到?復制到輸出緩沖區(qū),最后將其寫入輸出的壓縮zip或gz文件中。
數據從函數flush_pending中的待處理緩沖區(qū)復制到輸出緩沖區(qū)。當文字緩沖區(qū)已滿時,即表示已處理數據塊時,將調用此函數。在某些其他情況下,當需要刷新塊時也會調用它。復制到輸出緩沖區(qū)的數據長度受輸出緩沖區(qū)中的可用空間限制。
當。。。的時候?輸出緩沖區(qū)已滿,或何時?沖洗信號?發(fā)出后,zlib將輸出緩沖區(qū)寫入zip或gz文件。
zlib使用計數器pending_out和avail_out記錄未決緩沖區(qū)和輸出緩沖區(qū)中有多少字節(jié)可用。計數器值0表示緩沖區(qū)已滿。
相關代碼段:
flush_pending() {len = s->pending;if (len > strm->avail_out) len = strm->avail_out;if (len == 0) return;zmemcpy(strm->next_out, s->pending_out, len); } gzcomp() {if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&(flush != Z_FINISH || ret == Z_STREAM_END))) {have = (unsigned)(strm->next_out - state->x.next);if (have && ((got = write(state->fd, state->x.next, have)) < 0 || (unsigned)got != have)) {gz_error(state, Z_ERRNO, zstrerror());return -1;}if (strm->avail_out == 0) {strm->avail_out = state->size;strm->next_out = state->out;}} }4.優(yōu)化zlib
多家公司對通過優(yōu)化zlib的實施來提高壓縮性能感興趣。以下是一些摘要最近的相關作品。
4.1 英特爾:zlib-new
參考:英特爾:英特爾架構處理器上的高性能ZLIB壓縮(pdf)
優(yōu)化的重點在于改進的散列,在LZ77進程中搜索子串的最長前綴匹配以及Huffman代碼流。
改進的哈希:對于壓縮級別1到5,哈希元素為四元組(至少匹配4個字節(jié))。對于6到9的壓縮級別,請使用zlib的原始哈希元素作為三元組(至少匹配3個字節(jié))。
添加兩個其他策略:級別1為DEFLATE_quick,級別4至6為DEFLATE_medium。
- DEFLATE_quick:將哈希鏈搜索限制為第一個條目。
- DEFLATE_medium:旨在在zlib的壓縮率之間取得平衡?DEFLATE_slow?策略以及zlib的性能?DEFLATE_fast戰(zhàn)略。找到匹配項后,它將跳過匹配長度的轉發(fā),并支持延遲匹配評估的變體。當在位置p和長度l上找到匹配項時,在位置p + l + 1檢查匹配項。如果找到新的匹配項,則從position?p + l + 1向后掃描,以確定是否可以改善第二個匹配項。
哈希表移動速度更快:利用SSE(Intel?)一次對8個條目(16字節(jié))進行哈希移位。
更快的CRC計算:利用PCLMULQDQ(Intel?)指令以更改的算法一次處理64字節(jié)的輸入。
減少循環(huán)展開:消除了現代處理器上Adler32和CRC32計算中過多的循環(huán)展開。對于Adler32,將展開系數從16減小到8。對于CRC32,將展開系數從8減小到4。
4.2 IBM:快速放氣
參考:IBM:Deflate的快速實現
優(yōu)化的重點是通過使用LZ4的重復消除過程和改進的霍夫曼編碼過程來提高zlib放氣過程的速度。
用LZ4替換LZ77更快地消除重復:觀察到的提速是中等的,可能由于緩存使用率的差異而未達到LZ4的性能。還觀察到的壓縮比幾乎不受影響。
強制使用靜態(tài)霍夫曼樹:達到較快的速度,但可能對壓縮率產生負面影響。
半靜態(tài)霍夫曼編碼:使用靜態(tài)樹壓縮中間數據的第一個塊(LZ77的輸出),并收集該第一個塊的統計信息,以構建用于編碼后續(xù)塊的霍夫曼樹。第一個塊的大小是配置,默認大小是8KB。其他塊的大小也是可配置的,默認值為128KB。添加的另一個步驟是在構建霍夫曼樹之前確定初始塊的統計信息,以確定是否值得使用動態(tài)樹。這種方法既可以實現更快的速度,又可以實現更好的壓縮率。
4.3 臉書:Zstandard
參考:Facebook Zstandard(zstd)設計介紹
GitHub上的Zstandard
Zstandard旨在與現代硬件一起擴展,并壓縮得更快,更小,從而可以對各種數據類型進行通用壓縮。
通過結合幾種最新創(chuàng)新并針對現代硬件來改進zlib。
增加視窗大小?到1MB-8MB(推薦)。
壓縮使用?有限狀態(tài)熵?基于ANS(非對稱數字系統)的系統,以提高性能并減少延遲。
用?repcode建模?有效壓縮結構化數據
用一個?無分支設計風格?減少CPU分支預測器的開銷。
在解壓縮中,將數據分成多個并行流,并使用新一代的霍夫曼解碼器?并行解碼多個符號一個核心。這利用了現代CPU的能力,即每個周期可以發(fā)出多個指令。
4.4 Google:Zopfli,Brotli
參考:使用Zopfli的數據壓縮(pdf),Brotli,Deflate,Zopfli,LZMA,LZHAM和Bzip2壓縮算法的比較(pdf)
GitHub上的Zopfli
GitHub上的Brotli
Google在2013年推出了?佐普利,與deflate格式兼容。Zopfli給較小的壓縮數據大小?比gzip(小3.7-8.3%),但它具有?壓縮速度較慢?比gzip 9級高。Zopfli庫只能壓縮,不能解壓縮。
布羅特利?嘗試實施?新的壓縮格式,并且比放氣更有效。它的速度與放氣相似,但壓縮更緊密。
Brotli壓縮格式在RFC 7932中定義。該算法結合了LZ77算法的現代變體,霍夫曼編碼和二階上下文建模的組合。它還使用包含超過13K個單詞的靜態(tài)字典。靜態(tài)字典有助于壓縮短文件。
4.5 蘋果:LZFSE
參考:Apple數據壓縮:LZFSE
LZFSE專為iOS和macOS設計,以實現更高的能源效率和速度(介于2x和3x之間)。
LZFSE算法的用途?LZ77?和?有限狀態(tài)熵編碼。
4.6 CloudFlare:zlib
參考:CloudFlare與癌癥抗爭:開放源代碼帶來的意想不到的好處
GitHub上的CloudFlare zlib fork
CloudFlare對zlib的改進包括:
- 用?uint64_t?替換16位類型。
- 使用?改進的哈希函數iSCSI CRC32。此功能作為Intel處理器上的硬件指令實現。它具有非常快的性能和更好的碰撞性能。
- 搜索至少匹配的項?4字節(jié)。
- 使用SIMD指令?窗戶滾動。
- 使用Intel的硬件無攜帶乘法指令PCLMULQDQ?CRC32校驗和。
- 優(yōu)化的最長匹配功能。這是庫中對性能要求最高的功能。
尚未包含在已發(fā)布的zlib fork中的其他實驗:
- 使用zlib(哈希鏈)中使用的鏈表的改進版本
基準測試結果
- 測試數據集是四個標準語料庫數據,包括ASCII文本,位圖圖像,數字和源代碼文件。
- 速度:通常,CloudFlare的zlib比zlib和Intel的zlib快2至9級,尤其是6至9級(2倍-7.5倍)。
- 壓縮率:在所有級別上與zlib非常相似,并且在級別1上優(yōu)于Intel的zlib。
4.7 CloudFlare:預設字典
參考:CloudFlare:使用預設的deflate字典改善壓縮
優(yōu)化旨在提高HTML文件的壓縮性能(降低25%)(主要是?短文)。
將最小匹配長度更改為?4字節(jié)。
用一個?預設字典?因此在輸入的開頭有用于搜索匹配項的反向參考。
- 通過對一組要壓縮的文件執(zhí)行偽LZ77來創(chuàng)建預設字典,并在每個輸入文件的前16Kb中找到DEFLATE不會壓縮的字符串。然后對各個字符串進行頻率計數,并根據其長度和頻率對其進行評分。得分最高的字符串將保存到詞典文件中。
- 使用Go程序制作這樣的deflate字典:GitHub上的獨裁者
總結
以上是生活随笔為你收集整理的zlib库介绍四:zlib算法(LZ77、LZ78、霍夫曼编码、滑动窗口、Rabin-Karp算法、哈希链、I/O缓冲区)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 激活函数(activation func
- 下一篇: GSM/GPRS之一-GSM基础知识