2010-11-17 53 views
9

我在寫一個應用程序,它處理大量深度節點結構的xml文件(> 1000)。用woodstox(Event API)解析一個包含22.000個節點的文件需要大約6秒的時間。Java中的並行XML解析

該算法被放置在一個用戶交互過程中,只有幾秒的響應時間是可以接受的。所以我需要改進如何處理xml文件的策略。

  1. 我的進程分析xml文件(只提取幾個節點)。
  2. 處理已提取的節點,並將新結果寫入新的數據流(生成具有已修改節點的文檔副本)。

現在我正在考慮多線程解決方案(在16核心+硬件上可以更好地擴展)。我想到了以下幾種狀態:

  1. 創建多個解析器並在xml源文件上並行運行它們。
  2. 重寫我的分析算法線程保存使用解析器只有一個實例(工廠,...)
  3. 分割XML源成塊,並分配到大塊多個處理線程(map-reduce xml - serial
  4. 我的優化算法(更好的StAX解析器比woodstox?)/使用帶有內置的併發

我想提高這兩個解析器,整體性能和「每個文件」的表現。

您是否有這些問題的經驗?什麼是最好的方式去?

+0

目前尚不清楚這裏需要最大化什麼...... SINGLE文件的性能或所有1000個文件的總體性能。 – 2010-11-17 20:13:38

+0

還有一個建議:如果你可以量化文件的大小,允許計算整個(兆字節每秒處理)它可以給出預期性能的想法。在測試時,我通常會使用10到40 MB/s來解析Woodstox;但我的硬盤只能提供5 - 10 MB/s的持續速度。 – StaxMan 2010-12-21 23:17:04

+0

你看過vtd-xml嗎?它是重載加工中的藝術狀態......它比SAX或stax更有效率嗎? – 2016-05-02 06:53:42

回答

4
  1. 這一點很明顯:只需創建幾個解析器並在多個線程中並行運行它們。

  2. 看看Woodstox Performance(現在下來試試谷歌緩存)。

  3. 這可以完成如果你的XML的結構是可預測的:如果它有很多相同的頂級元素。例如:

    <element> 
        <more>more elements</more> 
    </element> 
    <element> 
        <other>other elements</other> 
    </element> 
    

    在這種情況下,你可以創建簡單的分路器,搜索<element>和飼料這部分特定的解析器實例。這是一個簡化的方法:在現實生活中,我會使用RandomAccessFile來查找起始停止點(<element>),然後創建僅在文件的一部分上運行的自定義FileInputStream。

  4. 看看Aalto。創造伍德斯托克的同樣的傢伙。這是這方面的專家 - 不要重蹈覆轍。

4

我同意吉姆。我認爲,如果你想提高1000個文件的整體處理性能,你的計劃是好的,除了在這種情況下不相關的#3。 如果你想提高解析單個文件的性能,你會遇到問題。我不知道如何在沒有解析的情況下拆分XML文件。每個塊都是非法的XML,你的解析器將會失敗。

我相信改善整體時間對您來說已經足夠了。在這種情況下閱讀本教程: http://download.oracle.com/javase/tutorial/essential/concurrency/index.html 然後創建線程池,例如100個線程和包含XML源的隊列。每個線程將僅解析10個文件,這將在多CPU環境中帶來嚴重的性能優勢。

+0

+1:如果解析非常簡單,主要問題是IO,它可能不會提高性能。 – 2010-11-17 22:59:23

2

除了現有的好建議,還有一件相當簡單的事情要做:使用遊標API(XMLStreamReader),而不是事件API。事件API增加了30-50%的開銷,沒有(只是IMO)顯着地使處理變得輕鬆。事實上,如果你想方便,我會建議使用StaxMate來代替;它建立在Cursor API的基礎之上,不會增加大量開銷(與手寫代碼相比最多5-10%)。

現在:我假設你已經對Woodstox做了基本的優化;但如果沒有,請查看「3 Simple Rules for Fast XML-processing using Stax」。具體來說,你絕對應該:

  1. 確保只創建的XMLInputFactory和XMLOutputFactory情況下,一旦
  2. 關閉讀者和作者,保證緩衝區回收(和其他有用的重用)按預期工作。

我提到這個的原因是雖然這些沒有功能差異(代碼按預期工作),但它們可以產生巨大的性能差異;儘管在處理較小的文件時更是如此。

運行多個實例也是有意義的;儘管通常每個核心最多隻有1個線程。但是,只有存儲I/O可以支持這種速度,您纔會受益;如果磁盤是瓶頸,這將無濟於事,並且在某些情況下可能會受到影響(如果磁盤爭用)。但值得一試。