XML解析到底能多快?

2021-06-07 17:10:12 字數 3725 閱讀 3937

【經驗總結】xml

解析到底能多快?

----by abllen

近來,因為工作的關係,需要對大xml檔案進行解析使用,就專門對解析效率問題作了下研究。 

場景:

在我們的場景中,會將大量的業務配置資訊存放在db, 便於前端修改, 後端使用時,會先將db匯出到本地xml格式檔案,再各自載入。 這裡之所以不直連資料庫一是考慮後端高併發時的效能問題,二是資料一般變動不頻繁,存放xml也合適。

起初也曾參考一些現有的xml解析庫,但由於我們的xml檔案都是從db匯出的,對有些情況不很合適,因而考慮手寫。

為什麼會手寫:

1)  允許xml的key為純數字,因為要從資料庫匯出到xml,而資料庫的內容往往難以避免有純數字的出現

2)  允許空key,資料庫裡往往使用空欄位表示預設,也比較方便

3)  相容xml格式,更好的出錯說明

我們希望使用完全的自左向右掃瞄分析,如對

能提示a/as

key缺少

>更好些, 而不是某一行缺少閉合的》不完整

tips:曾經對乙個800k的上萬行xml檔案進行排錯,包括notepad++/chrome/ie 等瀏覽器的出錯資訊讓人崩潰,往往只有  某一行缺少;等

4)  更好的把握

5)  學習,只有親手寫並和其他解析器對比,才能知道真正的瓶頸和問題在哪,希望能挖掘效能極限,看解析究竟能有多快

經過一段時間的調教,得到如下結果:

1)  俺的滿足系統要求的xml解析器核心**只有50行,純模板,外圍功能還支援增量解析合併,易用

2)  解析效能可以對比 strlen ,媲美rapidxml,是一般的tinyxml的數十倍。

關於rapidxml:

1)      號稱比tinyxml

快30~60倍,是boost.propertytree

的預設xml解析器

2)      對乙個約1.5m,utf-8編碼包含中/英文,有一定層次深度,大約3.3萬行的範例檔案解析 tinyxml: 54ms  而 rapidxml: 4ms!

(資料參考 

)3)      可對比strlen

ps:為什麼拿strlen對比,

由於解析一般都是對檔案字元進行的判斷處理,而strlen最簡單,且由於對0值判斷的特點,多數系統都採用了特別的優化,可以按系統位長(如32bit就是4位元組)來進行比較,效率很高並且是穩定的,可以作為基礎標尺。

測試及結論:

機器環境

系統win2003server + mingw gcc4.6.1

amd單核機器

1.8ghz 

記憶體ddr333 1g

(為了能明顯看出差異,特別動用了一台老爺機, 當然不用過於擔心現在機器的差異,拜amd不進取所致和頻率牆限制,intel那邊現在也是縫縫補補又三年,單核的效能這幾年幾乎沒有多少比例提高)

系統記憶體頻寬:

2.7gb/s  aida64 

記憶體讀取效能約

1200mb/s

(現在一般ddr3 1600的記憶體頻寬 12gb/s, aida64 檢測單通道讀取約5.8gb/s)

基準資料

範例檔案

1.5m

資料重複

1000

次,memcpy 3s

,strlen 2.8s

,自己寫的按位元組

mystrlen 12.1s

基本上自測的資料是上述aida64測試效能的再對半折,這裡面也可以看出x86的位元組不對齊影響不大。

自測結果

仍舊是範例檔案,

重複1000

次,rapidxml 14.2s

,myparse 14.1s

,與按位元組寫的

mystrlen

基本相當!!!

多出的主要是些邏輯判斷等,這應該是目前語言層面所能達到的基本極限了,更深的挖掘,可能需要考慮cpu擴充套件指令如sse的使用了,不過這類解析都是乙個前後關聯的過程,並行化並不容易。

如何做到的:

1)      只做一遍掃瞄分析,cpu的內部運算及頻寬相對記憶體還是快很多的,乙個字串多次比較和每次多個值比較會慢些,所以不要做多次子串的掃瞄,在測試中這減少了近2s

而一般的解析器為了簡單等原因,可能會對源串做多次子串操作,譬如當分析了乙個合規範的段後,剩餘內容子段化, a –

>  a

』 + b(a substr or erase a

』), 這裡面都可能包含大量的記憶體複製操作,會導致效能的迅速低下,如我優化前的解析器,效能就差50倍還多,快兩個量級。

2)      使用查表法換時間,當只做乙個自左至右的分析時,不可避免會對字串多次比較,

如』***

』 id2=

』yyy

』 />, 對key

abc每乙個字元的判斷,便不能為 \n \r \t space  = / >

使用查表法便可以解決這個速度問題,現代的cpu快取一般每核心都有二級256k, **2m,足夠快取錶值,見rapidxml 

file: rapidxml.hpp  version: 1.13  2423行

3)      模板程式設計可趨於減少執行時間,編譯器會優化掉中間的多層轉換及呼叫問題

4)      減少記憶體的分配,特別是小記憶體的頻繁分配釋放

在測試中只將每個key、id、value轉換成string,時間就已拉公升到了40ms左右,轉換到簡單dom樹要50ms,rapidxml則使用了自己特別的mempool(rapidxml只從記憶體解析,使用時會修改給定的記憶體段並複製),幾乎避免了記憶體的多次分配,時間也就幾乎保持了。

最後談一下文字與二進位制協議的看法:

1)  二進位制協議其實也要有拷貝及判斷等,極限情況下,只算一次比較及複製(二進位制也難以避免多次讀取判斷, 特別是字段複雜和多的情況下),按字元比較佔1/3算,需要

4×1/3 + 1×2/3= 2,即2倍strlen,加上更複雜的邏輯運算,僅比xml解析快一倍不到

2)  解析往往不是問題,儲存才是。rapidxml之所以快,還在於mempool的應用, 基本沒有記憶體的來回拷貝和小物件問題, 而一般的應用,包括我們的解析庫,最後都回到了對map類

stl的使用,stl不可避免會有多次的記憶體拷貝,加上中間小物件的頻繁分配釋放,效能會立馬降低幾倍,在這個比較上,純粹解析的差別就微乎其微。在實際的測試中,儲存往往會是乙個更大的影響, 而非解析。測試中, 將對映關係存入map,立即就到 ~50ms

3)  選擇自己喜歡的協議來吧,這真的不是太大問題, 建議不非常渴求的情況下, 使用字串或xml可讀性及可維護性好的協議

4)  對於簡單又短小的協議,可用二進位制

5)  一家之言,歡迎pk討論j

本文原創自無線技術運營空間:  

及  (專注無線技術運營

——無線技術

(作業系統

/資料庫

/web前端/

負載均衡

/系統容災

/系統安全

/簡訊接入

/wap

接入/3g等)

、無線業務運營、無線開放平台、統計分析

(使用者行為分析

/資料探勘)、

[email protected]) 

fseek讀,到底有多快!

常聽人說,fseek很快 到底多快?如果不知道多快,就乙個勁的爭論很快!好像不必擔心的快一樣。這種常識性的東西不知道,妄談系統設計,就會出笑話的。下面做個實驗,測測fseek的量級。測試的方法 1.乙個檔案512m 2.乙個執行緒對應乙個檔案,然後在這個檔案裡邊進行rand fseek,然後讀1k位...

CAN FD的波特率到底能跑多快?

摘要 canfd是基於can20的公升級版協議,為了滿足汽車電子日益增長的高頻寬和高傳輸速率的要求,canfd主要公升級了以下幾個方面 眾所周知,can fd是基於can 2.0的公升級版協議,為了滿足汽車電子日益增長的高頻寬和高傳輸速率的要求,can fd主要公升級了以下幾個方面 一 更高的傳輸波...

記憶體資料庫到底有多快

併發量太高的應用中 比如10分鐘內插入300w條記錄 資料庫往往難堪重負,在沒有銀子實現伺服器集群 負載均衡 分布式儲存的情況下,可以嘗試一下把資料庫做乙個臨時副本全部放在記憶體中處理,完成操作後,再同步到硬碟的物理資料庫中。那麼,把資料庫放在記憶體中到底有多快?晚上抽空試了一下 步驟1 先用ram...