Json海量數據解析

Json海量數據解析

前言

? 在android開發中,app和服務器進行數據傳輸時大多數會用到json。在解析json中通常會用到以下幾種主流的解析庫:jackson、gson、fastjson。而對于從server端獲取的數據量很小時候,我們可能會忽略解析所產生的性能問題。而我在開發的過程中就碰到因為解析json而產生嚴重的問題。

問題場景

先描述以下問題的場景:app做收銀庫存管理。這時候每次登陸時候會去服務端同步所有的商品、分類等數據。而這時候,當商品的數量很大的時候,客戶端拿到數據時候對app來說還是比較大的。而server端是將所有的數據序列化為json字符串存入到文件,然后app去下載文件并進行解析。下面說下我的修改歷程。

踩坑過程

  • 第一版代碼是直接講文件讀出為字符串,使用gson直接反序列化 new Gson().fromJson(String s,Type type)這時候OOM,查看日志,發現文件讀出字符串時候直接OOM了(當初并沒有考慮會有這么大的數據,暈倒)。從server端下載下來的文件就有20M左右。
  • 第二版代碼使用FastJson的JSONReader。對每個對象進行單獨序列化。也就是下面講到的fastjson方法1。這時候OOM問題的解決了。因為是讀的文件流,邊讀邊解析數據。基本解決了問題。但通過Android Studio的Monitors發現,解析時候內存不斷的在被消耗(汗。。還好沒有爆掉)。
  • 第三版代碼使用Fastjson的JSONReader。對每個json的每個key每個value都單獨的解析和讀取。也就是下面講到的fastjson方法2。這時候所有的性能問題全部解決,速度最快,幾乎沒有消耗多少內存。

? 上面是我一步步走過得坑,唉。可能對于看過fastjson源碼的童鞋來說so easy。但第一次碰到后,坑還是得一步步的踩。當然也是要不斷的通過看源碼、寫測試代碼、比較內存和時間。下面是我做的一些測試。

測試驗證

準備工作
  • 相關依賴庫

        compile group: 'com.alibaba', name: 'fastjson', version: '1.2.29'
        // https://mvnrepository.com/artifact/commons-io/commons-io
        compile group: 'commons-io', name: 'commons-io', version: '2.5'
        // https://mvnrepository.com/artifact/com.google.code.gson/gson
        compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0's
    
  • 測試數據生成

        public void createDataFile() {
            List<Good> goodList = new ArrayList<>();
            for (int i = 0; i < 200000; i++) {
                Good good = new Good(System.currentTimeMillis() + "_" + i,
                        new String("booke") + i, 10.f + i,
                        System.currentTimeMillis() + "",
                        "describe book" + i,
                        i);
                goodList.add(good);
            }
            try {
                String json = JSONArray.toJSONString(goodList);
                FileUtils.write(new File("e://goods.json"), json, "UTF-8");
            } catch (IOException e) {
                log("" + e.getMessage());
                e.printStackTrace();
            }
        }
    
結果分析
  • gson解析

    使用流進行讀取。20W條數據,內存不斷的被消耗。兩次解析時間為 50,488ms、48,940ms 性能是相當的差

List<Good> list = new Gson().fromJson(new InputStreamReader(getAssets().open("goods.json"),     
            "UTF-8"), new TypeToken<List<Good>>() {}.getType());
1.png
  • fastjson方法1

使用流進行讀取。內存也是不斷被消耗。三次解析時間為 33,394ms 31,632ms 32,378ms

JSONReader reader = new JSONReader(new InputStreamReader(getAssets().open("goods.json"),
            "UTF-8"));
reader.startArray();
while (reader.hasNext()) {
    Good good = reader.readObject(Good.class);
}
reader.endArray();
reader.close();
reader = null;
2.png
  • fastjson方法2

    使用流進行讀取,每個key和value自己來處理。三次解析時間為 31,242ms 31,583ms 30,834ms。同時,內存幾乎沒有太多的占用,比較的平穩。這個方法當然最優。

JSONReader reader = new JSONReader(new InputStreamReader(getAssets().open("goods.json"),
           "UTF-8"));
reader.startArray();
while (reader.hasNext()) {
    reader.startObject();
    Good good = new Good();
    while (reader.hasNext()) {
        String key = reader.readString();
        if ("id".equals(key)) {
                good.setId(reader.readString());
            } else if ("name".equals(key)) {
                good.setName(reader.readString());
            } else if ("price".equals(key)) {
                good.setPrice(Double.parseDouble(reader.readString()));
            } else if ("barCode".equals(key)) {
                 good.setBarCode(reader.readString());
            } else if ("desc".equals(key)) {
                 good.setDesc(reader.readString());
            } else if ("count".equals(key)) {
                 good.setCount(Integer.parseInt(reader.readString()));
            } else {
                 reader.readObject();
            }   
        }
    reader.endObject();
    }
reader.endArray();
reader.close();
reader = null;
3.png

最后我們對比消耗時間

5.png

其他

  • Good.java
public class Good {
  private String id;
  private String name;
  private double price;
  private String barCode;
  private String desc;
  private int count;
  public Good() {
  }
  public Good(String id, String name, double price, String barCode, String desc, int count) {
      this.id = id;
      this.name = name;
      this.price = price;
      this.barCode = barCode;
      this.desc = desc;
      this.count = count;
  }
  public String getId() {
      return id;
  }
  public void setId(String id) {
      this.id = id;
  }
  public String getName() {
      return name;
  }
  public void setName(String name) {
      this.name = name;
  }
  public double getPrice() {
      return price;
  }
  public void setPrice(double price) {
      this.price = price;
  }
  public String getBarCode() {
      return barCode;
  }
  public void setBarCode(String barCode) {
      this.barCode = barCode;
  }
  public String getDesc() {
      return desc;
  }
  public void setDesc(String desc) {
      this.desc = desc;
  }
  public int getCount() {
      return count;
  }
  public void setCount(int count) {
      this.count = count;
  }
  @Override
  public String toString() {
      return "Good{" +
              "id='" + id + '\'' +
              ", name='" + name + '\'' +
              ", price=" + price +
              ", barCode='" + barCode + '\'' +
              ", desc='" + desc + '\'' +
              ", count=" + count +
              '}';
  }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評論 6 545
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,795評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,943評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,057評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,773評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,106評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,282評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,793評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,507評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,741評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,929評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,325評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,661評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,482評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,702評論 2 380

推薦閱讀更多精彩內容