jsoncpp与rapidjson易用性与性能评测

2023-05-16

文章目录

  • jsoncpp与rapidjson易用性与性能评测
    • 1. 概述
    • 2. 易用性
      • 2.1 jsoncpp
      • 2.2 rapidjson
    • 3. 性能
    • 4.总结

jsoncpp与rapidjson易用性与性能评测

1. 概述

jsoncpp和rapidjson是两款常用C++11编写的第三方开源JSON序列化与反序列化库, 两者都基于MIT协议发布,对商用较友好,以下从使用上和性能上对两者做出评价,方便不同应用场景选择。

2. 易用性

2.1 jsoncpp

  • 头文件源文件并存: 一般根据平台编译成动态库引入项目;
  • 中间对象JSON value:构造较容易,使用较方便。

2.2 rapidjson

  • 纯头文件: rapidjson只包含头文件,不包含源文件,非常方便集成到项目中;
  • 中间对象JSON value: 构造较复杂, 涉及到内存分配器;
  • 自包含:rapidjson完全是一个独立的项目,不依赖与第三个库,比如不依赖BOOST,甚至可以不依赖STL;
  • 速度快:性能类似于strlen()。

在使用上jsoncpp更胜一筹,性能上rapidjson更好(见3.性能):
jsoncpp中,根节点和子节点都是用Json::Value, 且很方便使用[]操作符操作子节点,节点不存在则新建,存在则引用,而rapidjson只能在节点存在的情况下才能使用[], 否则断言失败,简单举例如下:
序列化_serialize

// jsoncpp
Json::Value root;

Json::Value value;
value["string"] = "hello world";
root.append(std::move(value));

Json::FastWriter writer;
std::string json = writer.write(root);

//rapidjson
rapidjson::Document doc;
Document::AllocatorType &alloc = doc.GetAllocator();

doc.SetArray(); //必须,否则断言错误
rapidjson::Value value(kObjectType); //或者value.SetObject();
value.AddMember("string", "hello world", alloc); //不能使用value["string"],会断言失败
doc.PushBack(value, alloc);

rapidjson::StringBuffer buffer; //对buffer内存的释放只能析构,使用clear方法只能改变size,不能改变capacity, 类似于std::vector
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
doc.Accept(writer);
std::string json = buffer.GetString();

//json 输出
[
    {
        "string": "hello world"
    }
]

特别地,rapidjson::Document为文档对象,即根节点,rapidjson::Value为一般节点,归属于根节点;虽然rapidjson::Document继承自rapidjson::Value,但存在两个不同的节点表示和使用方式,并且全文涉及内存分配器,使用难度稍大一点,一不小心容易内存泄漏,千万记住doc一定要释放, 否则由doc的分配器分配出来的内存是不会自动释放的,如果应用一直服用一个doc,则top会清晰地观察到内存不断增长, 如果不关心中间对象,rapidjson提供了另一种直接的方式进行序列化,直接序列化,不经过JSON value, 如下:

//rapidjson
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.StartArray(); //"["
writer.StartObject();// "{"
writer.key("string");// "string":
writer.String("hello world"); //"hello world"
writer.EndObject(); //"}"
writer.EndArray(); //"]"

std::string json = buffer.GetString();

反序列化_deserialize

//json 输入
[
    {
        "string": "hello world"
    }
]
//jsoncpp
std::string str;
Json::Value root;
Reader reader(Json::Features::strictMode());
if (reader.parse(str, root)) {
    //解析成功
    if (root.isArray() && !root.empty()) {
        auto size = root.size();
        for (uint32_t i = 0; i < size; i++)
        {
            if (root[i].isObject && root[i].isMember("string")) {
                str = root[i]["string"].isString() ? root[i]["string"].asString() : "";
            }
        }
    }
}
//rapidjson
std::string str;
rapidjosn::Document doc;
if (!doc.Parse(data, size).HasParseError()) {
   //解析成功
    if (doc.IsArray()) {
        auto arr = root.GetArray();
        for (auto &val : arr)
        {
            if (val.IsObject()) {
                auto it = val.FindMember("string");
                if (it != val.MemberEnd()) {
                    if (it->value.IsString()) { //等价于val["string"]
                        str = std::string(it->value.GetString(), it->value.GetStringLength);
                    }
                }
            } 
        }
    }
}

#if 0 //原位解析-更快
rapidjson::InsituStringStream iss(const_cast<char *>(json.c_str());
if (!doc.ParseStream<rapidjson::kParseDefaultFlags | rapidjson::kParseStopWhenDoneFlag | rapidjson::kParseInsituFlag>(iss).HasParseError()) {
    //解析成功
}
#endif

以上,jsoncpp和rapidjson反序列化流程基本一致,操作也很接近,但是rapidjson解析速度更快,辅以原位解析(in situ parsing), 性能可以做到极致。

3. 性能

测试版本:

  • rapidjson: 1.1.0
  • jsoncpp: 1.8.0
  • test.json
    [{“map_key”:1,“id”:1,“desc”:“配置方案1”,“cycle”:100,“offset”:0,“coordPhase”:1,“timing”:[{“phase”:1,“time”:10,“status”:0,“barrier”:1},{“phase”:2,“time”:10,“status”:0,“barrier”:1},{“phase”:3,“time”:10,“status”:0,“barrier”:1},{“phase”:4,“time”:10,“status”:0,“barrier”:1},{“phase”:5,“time”:15,“status”:0,“barrier”:1},{“phase”:6,“time”:15,“status”:0,“barrier”:1},{“phase”:7,“time”:15,“status”:0,“barrier”:1},{“phase”:8,“time”:15,“status”:0,“barrier”:1},{“phase”:9,“time”:12,“status”:0,“barrier”:1},{“phase”:10,“time”:13,“status”:0,“barrier”:1},{“phase”:11,“time”:12,“status”:0,“barrier”:1},{“phase”:12,“time”:13,“status”:0,“barrier”:1},{“phase”:13,“time”:12,“status”:0,“barrier”:1},{“phase”:14,“time”:13,“status”:0,“barrier”:1},{“phase”:15,“time”:12,“status”:0,“barrier”:1},{“phase”:16,“time”:13,“status”:0,“barrier”:1},{“phase”:17,“time”:12,“status”:0,“barrier”:1},{“phase”:18,“time”:13,“status”:0,“barrier”:1},{“phase”:19,“time”:12,“status”:0,“barrier”:1},{“phase”:20,“time”:13,“status”:0,“barrier”:1},{“phase”:21,“time”:12,“status”:0,“barrier”:1},{“phase”:22,“time”:13,“status”:0,“barrier”:1},{“phase”:23,“time”:12,“status”:0,“barrier”:1},{“phase”:24,“time”:13,“status”:0,“barrier”:1},{“phase”:25,“time”:12,“status”:0,“barrier”:1},{“phase”:26,“time”:13,“status”:0,“barrier”:1},{“phase”:27,“time”:12,“status”:0,“barrier”:1},{“phase”:28,“time”:13,“status”:0,“barrier”:1},{“phase”:29,“time”:12,“status”:0,“barrier”:1},{“phase”:30,“time”:9,“status”:0,“barrier”:1},{“phase”:31,“time”:10,“status”:0,“barrier”:1},{“phase”:32,“time”:19,“status”:0,“barrier”:1},{“phase”:33,“time”:6,“status”:0,“barrier”:1},{“phase”:34,“time”:94,“status”:0,“barrier”:1},{“phase”:35,“time”:50,“status”:0,“barrier”:1},{“phase”:36,“time”:50,“status”:0,“barrier”:1},{“phase”:37,“time”:50,“status”:0,“barrier”:1},{“phase”:38,“time”:50,“status”:0,“barrier”:1},{“phase”:39,“time”:100,“status”:0,“barrier”:1}],“turn”:[[1,2,3,4,5,6,7,8],[9,10,11,12,13,14,15,16],[17,18,19,20,21,22,23,24],[25,26,27,28,29,30,31,32],[33,34],[35,36],[37,38],[39]]},…+64(重复64次) 126KB

测试主机arm-linux, 单核, 128M, 400MHZ, at91sam9x25(arm926)平台

arm-at91-linux-gnueabi-g++ -std=c++11 -Wall

-JSON -> ValueValue -> TJSON -> TT -> ValueValue -> JSONT -> JSON
jsoncpp1s 778ms 593us0s 426ms 634us2s 262ms 984us1s 375ms 353us1s 376ms 462us2s 867ms 207us
rapidjson0s 255ms 710us0s 165ms 277us0s 426ms 507us0s 180ms 312us0s 146ms 775us0s 249ms 457us
rapidjson(in situ)0s 199ms 849us-0s 365ms 60us---

arm-at91-linux-gnueabi-g++ -std=c++11 -Wall -O3

-JSON -> ValueValue -> TJSON -> TT -> ValueValue -> JSONT -> JSON
jsoncpp0s 570ms 701us0s 80ms 454us0s 661ms 160us0s 417ms 534us0s 716ms 88us1s 131ms 268us
rapidjson0s 33ms 829us0s 20ms 865us0s 56ms 863us0s 40ms 434us0s 21ms 870us0s 59ms 594us
rapidjson(in situ)0s 31ms 48us-0s 55ms 364us---

T: 结构体
JSON: 字符串
Value: json对象

4.总结

  • 优先考虑使用性,选择jsoncpp;
  • 优先考虑性能,速度,选择rapidjson;
  • 均使用-O3优化。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

jsoncpp与rapidjson易用性与性能评测 的相关文章

随机推荐