美文网首页java
Json海量数据解析

Json海量数据解析

作者: 第八区 | 来源:发表于2017-03-28 23:53 被阅读482次

    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 +
                  '}';
      }
    }
    

    相关文章

      网友评论

        本文标题:Json海量数据解析

        本文链接:https://www.haomeiwen.com/subject/aagsottx.html