1. 程式人生 > >Jackson和FastJson效能誰更快

Jackson和FastJson效能誰更快

前言

jackson和fastjson大概是我們使用得最多的兩個json序列化包和反序列化包。網上的效能對比很多,大多數的結果對fastjson都不利,甚至有的結論是比Gson還要慢,但是我覺得fastjson是阿里系的,應該效能不會差,於是作了一系列對比。我們這裡使用的是最新的兩個包jackjson為2.8版本,而fastjson為1.2.14版本

對比使用物件

在對比中使用的物件基本包含了所有的資料型別和集合,並且是隨機生成。這裡我直接借鑑了別人測試的時候使用的物件,因為的確比較好,我便沒有修改,程式碼如下:

/**
 * Created by lz on 2016/7/23.
 */
import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; /** * 該類提供生成樣本的元資料 * */ public class DataBuilder { private static final String[] chars = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8"
, "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
}; private static final int charNum = 62; // 樣本String最大長度 private static final int maxStrLength = 100; // 樣本String預設長度 private static final int defaultStrLength = 50; // 樣本List最大長度 private static final int maxListSize = 100; // 樣本List預設長度 private static final int defaultListSize = 10; // 樣本Map最大Key數量 private static final int maxMapSize = 100; // 樣本Map預設Key數量 private static final int defaultMapSize = 10; // 樣本Map中Value的資料型別 private static final String[] types = new String[] { "boolean", "int", "long", "double", "date", "string"}; private static final int typeNum = 6; private static final Random random = new Random(); /** * 生成隨機長度的字串 * @return 字串 */ public static String randomString(){ return randomString(random.nextInt(maxStrLength)); } /** * 生成指定長度的字串 * @param len 字串長度 * @return */ public static String randomString(int len) { if (len < 1 || len > maxStrLength) { // 如果字串長度超出範圍,使用預設長度 len = defaultStrLength; } StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) { sb.append(chars[random.nextInt(charNum)]); } return sb.toString(); } /** * 生成List樣本,List中元素的數量隨機 * @return */ public static List<String> randomStringList() { return randomStringList(random.nextInt(maxListSize)); } /** * 生成List樣本 * @param size List中元素的數量 * @return */ public static List<String> randomStringList(int size) { if (size < 1 || size > maxListSize) { size = defaultListSize; } List<String> list = new ArrayList<String>(); for (int i = 0; i < size; i++) { list.add(randomString(random.nextInt(maxStrLength))); } return list; } /** * 生成隨機Map樣本,樣本中key的數量隨機 * @return */ public static Map<String, Object> randomMap() { return randomMap(random.nextInt(maxMapSize)); } /** * 生成隨機Map樣本 * @param size 樣本中key的數量 * @return */ public static Map<String, Object> randomMap(int size) { if (size < 1 || size > maxMapSize) { size = defaultMapSize; } Map<String, Object> map = new HashMap<String, Object>(); for (int i = 0; i < size; i++) { String type = types[random.nextInt(typeNum)]; if ("boolean".equals(type)) { map.put("key" + i, random.nextBoolean()); } else if ("int".equals(type)) { map.put("key" + i, random.nextInt()); } else if ("long".equals(type)) { map.put("key" + i, random.nextLong()); } else if ("double".equals(type)) { map.put("key" + i, random.nextDouble()); } else if ("date".equals(type)) { map.put("key" + i, new Date()); } else if ("string".equals(type)) { map.put("key" + i, randomString(random.nextInt(maxStrLength))); } } return map; } }

以及

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * 樣本物件
 *
 */
public class JsonObject implements Serializable {
    private static final long serialVersionUID = -1520171788566678009L;

    private Boolean fieldBoolean;
    private Integer fieldInt;
    private Long fieldLong;
    private Double fieldDouble;
    private Date fieldDate;
    private String fieldStr;
    private List<String> fieldList;
    private Map<String, Object> fieldMap;

    /**
     * 隨機樣本
     */
    public JsonObject() {
        Random random = new Random();

        fieldBoolean = random.nextBoolean();
        fieldInt = random.nextInt();
        fieldLong = random.nextLong();
        fieldDouble = random.nextDouble();
        fieldDate = new Date();
        fieldStr = DataBuilder.randomString();

        fieldList = DataBuilder.randomStringList();

        fieldMap = DataBuilder.randomMap();
    }

    /**
     * 指定List元素數量和Map元素數量的樣本
     * @param listSize List元素數量
     * @param mapKeyNum Map元素數量
     */
    public JsonObject(int listSize, int mapKeyNum) {
        Random random = new Random();

        fieldBoolean = random.nextBoolean();
        fieldInt = random.nextInt();
        fieldLong = random.nextLong();
        fieldDouble = random.nextDouble();
        fieldDate = new Date();
        fieldStr = DataBuilder.randomString();

        fieldList = DataBuilder.randomStringList(listSize);

        fieldMap = DataBuilder.randomMap(mapKeyNum);
    }

    public Boolean getFieldBoolean() {
        return fieldBoolean;
    }

    public void setFieldBoolean(Boolean fieldBoolean) {
        this.fieldBoolean = fieldBoolean;
    }

    public Integer getFieldInt() {
        return fieldInt;
    }

    public void setFieldInt(Integer fieldInt) {
        this.fieldInt = fieldInt;
    }

    public Long getFieldLong() {
        return fieldLong;
    }

    public void setFieldLong(Long fieldLong) {
        this.fieldLong = fieldLong;
    }

    public Double getFieldDouble() {
        return fieldDouble;
    }

    public void setFieldDouble(Double fieldDouble) {
        this.fieldDouble = fieldDouble;
    }

    public Date getFieldDate() {
        return fieldDate;
    }

    public void setFieldDate(Date fieldDate) {
        this.fieldDate = fieldDate;
    }

    public String getFieldStr() {
        return fieldStr;
    }

    public void setFieldStr(String fieldStr) {
        this.fieldStr = fieldStr;
    }

    public List<String> getFieldList() {
        return fieldList;
    }

    public void setFieldList(List<String> fieldList) {
        this.fieldList = fieldList;
    }

    public Map<String, Object> getFieldMap() {
        return fieldMap;
    }

    public void setFieldMap(Map<String, Object> fieldMap) {
        this.fieldMap = fieldMap;
    }

}

測試方法

我們的測試策略如下:
輸入需要測試的個數,例如輸入10000,然後會對此進行測試10次,按照國際慣例去掉時間最小的,和一個時間最大的,剩下的8次再來求平均值,得到的就是我們所要求得平均速度,這裡我們需要測試10個數據 1000個數據 10萬個資料。程式碼如下:

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 測試方法
 * 輸入需要測試的個數
 * 例如輸入10000
 * 然後會對此進行測試10次,去掉時間最小的,和一個時間最大的,剩下的8次再來求平均值
 * 得到的就是我們所要求得平均速度
 * 這裡我們需要測試10個數據 1000個數據 10萬個資料
 * Created by lz on 2016/7/24.
 */
public class TestMain {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 傳入資料的個數
     * @param nums
     * @return
     */
    public static List<Double> complete(int nums) throws Exception {
        Double[] jacksonTimes = new Double[10];
        Double[] fastjsonTimes = new  Double[10];
        Double[] jacksonTimes1 = new Double[10];
        Double[] fastjsonTimes1 = new  Double[10];
        List<Double> time = new ArrayList<Double>();
        for (int i = 0; i < 10 ; i++) {
            List<Double> list = getTime(nums);
            jacksonTimes[i]=list.get(0);
            fastjsonTimes[i]=list.get(1);
            jacksonTimes1[i]=list.get(2);
            fastjsonTimes1[i]=list.get(3);
        }
        Arrays.sort(jacksonTimes);
        Arrays.sort(fastjsonTimes);
        Arrays.sort(jacksonTimes1);
        Arrays.sort(fastjsonTimes1);
        Double sum = 0.00;
        for (int i = 1; i < 9; i++) {
            sum += jacksonTimes[i];
        }
        time.add(sum/8);
        sum=0.00;
        for (int i = 1; i < 9; i++) {
            sum += fastjsonTimes[i];
        }
        time.add(sum/8);
        sum=0.00;
        for (int i = 1; i < 9; i++) {
            sum += jacksonTimes1[i];
        }
        time.add(sum/8);
        sum=0.00;
        for (int i = 1; i < 9; i++) {
            sum += fastjsonTimes1[i];
        }
        time.add(sum/8);
        return time;
    }

    /**
     * 傳入資料的個數
     * @param nums
     * @return list.get(0)是jackson本次的時間 list.get(1)是fastjson本次的時間
     */
    public static List<Double> getTime(int nums) throws Exception {
        Double jacksonTime1 = 0.00;
        Double fastjsonTime1 = 0.00;
        Double jacksonTime2 = 0.00;
        Double fastjsonTime2 = 0.00;
        for (int i = 0; i < nums; i++) {
             //這裡我們生成jsonObject
            JsonObject  jsonObject = new JsonObject();
            long start,end;
            String str = null;
            start = System.currentTimeMillis();
            str = OBJECT_MAPPER.writeValueAsString(jsonObject);
            end = System.currentTimeMillis();
            jacksonTime1 += Double.valueOf(end-start);
            start = System.currentTimeMillis();
            str = JSON.toJSONString(jsonObject);
            end = System.currentTimeMillis();
            fastjsonTime1 += Double.valueOf(end-start);
            start = System.currentTimeMillis();
            OBJECT_MAPPER.readValue(str, JsonObject.class);
            end = System.currentTimeMillis();
            jacksonTime2 += Double.valueOf(end-start);
            start = System.currentTimeMillis();
            JSON.parseObject(str,JsonObject.class);
            end = System.currentTimeMillis();
            fastjsonTime2 += Double.valueOf(end-start);
        }
        List<Double> list = new ArrayList<Double>();
        list.add(jacksonTime1);
        list.add(fastjsonTime1);
        list.add(jacksonTime2);
        list.add(fastjsonTime2);
        return list;
    }
    public static void main(String[] args) throws Exception {
        //輸入測試個數,得到時間
        List<Double> list10 = complete(10);
        List<Double> list1000 = complete(1000);
        List<Double> list100000 = complete(100000);
        System.out.println("------------------------序列化時間比較----------------------------");
        System.out.println("測試資料為10的時候:jackson序列化時間:"+list10.get(0)+"ms | fastjson序列化時間"+list10.get(1)+"ms");
        System.out.println("測試資料為1000的時候:jackson序列化時間:"+list1000.get(0)+"ms | fastjson序列化時間"+list1000.get(1)+"ms");
        System.out.println("測試資料為100000的時候:jackson序列化時間:"+list100000.get(0)+"ms | fastjson序列化時間"+list100000.get(1)+"ms");
        System.out.println("------------------------反序列化時間比較----------------------------");
        System.out.println("測試資料為10的時候:jackson反序列化時間:"+list10.get(2)+"ms | fastjson反序列化時間"+list10.get(3)+"ms");
        System.out.println("測試資料為1000的時候:jackson反序列化時間:"+list1000.get(2)+"ms | fastjson反序列化時間"+list1000.get(3)+"ms");
        System.out.println("測試資料為100000的時候:jackson反序列化時間:"+list100000.get(2)+"ms | fastjson反序列化時間"+list100000.get(3)+"ms");
    }
}

最後的結果:
————————序列化時間比較—————————-
測試資料為10的時候:jackson序列化時間:5.0ms | fastjson序列化時間4.75ms
測試資料為1000的時候:jackson序列化時間:61.375ms | fastjson序列化時間45.875ms
測試資料為100000的時候:jackson序列化時間:2448.875ms | fastjson序列化時間2421.375ms
————————反序列化時間比較—————————-
測試資料為10的時候:jackson反序列化時間:13.0ms | fastjson反序列化時間9.25ms
測試資料為1000的時候:jackson反序列化時間:148.375ms | fastjson反序列化時間133.625ms
測試資料為100000的時候:jackson反序列化時間:9488.625ms | fastjson反序列化時間9356.75ms

結論

有時候,別人做的東西還真的不能信,必須要自己親身體驗測試過才知道速度的快慢,fastjson並不是像很多人說的速度要慢很多,基本序列化時間和反序列化時間都是55開的甚至fastjson可能要略勝與jackson。
github地址:https://github.com/lzggsimida123/json1

更多交流請掃我的技術公眾號

我的技術公眾號