jsonCpp使用介绍和优化
JsonCpp简介
注意: Json::Value只能处理ANSI类型的字符串,如果C++程序使用Unicode编码的,最好加一个Adapt类来适配。 简单解析例子:数据格式为: { "status":"ok", "data": { "id":"18135798", "name":"u6b27u9ea6u560eu5730", "avatar":"http://u1.qhimg.com/qhimg/quc/48_48/22/02/55/220255dq9816.3eceac.jpg?f=6c449fbaaa093e52b4053e46170af079", "sex":"u672au77e5", "area":"", "nick":"","access_token":"49395625948d4d6f253203e8aa8f3316150290e9d57be59b2","refresh_token":"493956259454b771dba785feeafb01221858440f4c811b5ad" }, "common": { "channel":"000023","user_sdk":"360","uid":"18135798" "server_id":"" }, "ext":"" }
//解析json int32_t index = reponse_data.find("{"); if(-1 != index) { string in_data = reponse_data.substr(index,reponse_data.size()-index); Json::Reader reader; Json::Value value; if(reader.parse(in_data,value)) { if(value["status"].asString() == "ok") { if(!value["data"].isNull()) { Json::Value data = value["data"]; if (!data["nickname"].isNull()) { const char *name = data["nickname"].asCString(); memcpy(plat_user->nick_name_,name,strlen(name)); } if (!data["token"].isNull()) { const char *token = data["token"].asCString(); memcpy(s_data->token,token,strlen(token)); s_data->token[32] = ' '; } } if(!value["common"].isNull()) { Json::Value data = value["common"]; if (!data["channel"].isNull()) { const char *channel = data["channel"].asCString(); memcpy(s_data->plat,channel,strlen(channel)); } if (!data["uid"].isNull()) { const char *uid = data["uid"].asCString(); memcpy(plat_user->user_id_,uid,strlen(uid)); } } return 0; } else { return -1; } } } 下载和编译本文运行环境是: Redhat 5.5 + g++version 4.6.1 + GNU Make 3.81 + jsoncpp-0.5.0 下载地址是:http://sourceforge.net/projects/jsoncpp/ 解压之后得到jsoncpp-src-0.5.0文件夹,我们只需要jsoncpp的头文件和cpp文件,其中jsonscpp的头文件位于jsoncpp-src-0.5.0includejson,jsoncpp的cpp文件位于jsoncpp-src-0.5.0srclib_json。 这里我列出我们的工作目录: jsoncpp/ //工作目录 |-- include //头文件根目录 | |-- json //json头文件,对应jsoncpp-src-0.5.0includejson |-- src //cpp源码文件根目录 |-- json //jsoncpp源码文件,对应jsoncpp-src-0.5.0srclib_json |-- main.cpp //我们的主函数,调用jsoncpp的示例代码 |-- makefile //makefile,不用我们多说了吧,不懂请看我博客的makefile最佳实践 反序列化Json对象假设有一个json对象如下: { "name": "json″,"array": [ { "cpp": "jsoncpp" },{ "javajsoninjavaphpsupport" } ] }我们要实现这个json的反序列化代码如下: void readJson() { using namespace std; std::string strValue = "{"name":"json","array":[{"cpp":"jsoncpp"},{"java":"jsoninjava"},{"php":"support"}]}"; Json::Reader reader; Json::Value value; if (reader.parse(strValue,value)) { std::string out = value["name"].asString(); std::cout << out << std::endl; const Json::Value arrayObj = value["array"]; for (unsigned int i = 0; i < arrayObj.size(); i++) { if (!arrayObj[i].isMember("cpp")) continue; out = arrayObj[i]["cpp"].asString(); std::cout << out; if (i != (arrayObj.size() - 1)) std::cout << std::endl; } } } 序列化Json对象void writeJson() { using namespace std; Json::Value root; Json::Value arrayObj; Json::Value item; item["cpp"] = "jsoncpp"; item["java"] = "jsoninjava"; item["php"] = "support"; arrayObj.append(item); root["name"] = "json"; root["array"] = arrayObj; root.toStyledString(); std::string out = root.toStyledString(); std::cout << out << std::endl; } JsonCpp使用优化
最近一个项目在使用JsonCpp,JsonCpp简洁易用的接口让人印象深刻。但是在实际使用过程中,我发现JsonCpp的性能却不尽如人意,所以想着方法优化下性能。 代码理解1、JsonCpp中一切都是Value,Value用union指向自己保存的数据。Value的类型分为两种,一种是容器类型,比如arrayValue和objectValue。二者都是用map保存数据,只是arrayValue的key为数字而已。另外一种是基本类型,比如字符串,整型数字等等。 2、解释JSON数据时,JsonCpp在operator[]函数开销比较大。JsonCpp内部使用std::map,map在查找性能上不如hash_map,但是将map替换成hash_map有一定的困难,因为map的key为CZString,而这个类又是Value的内部类,导致不能定义hash_map需要的hash结构体。 本来想尝试下internal map,结果开启JSON_VALUE_USE_INTERNAL_MAP这个宏之后,根本通不过编译,因为value.h中有一处uion声明里面居然放的是结构体,不知道什么编译器支持这种语法。 基准测试程序 #include <iostream> #include <string> #include <sys/time.h> #include <time.h> #include <json/json.h> using namespace std; int64_t getCurrentTime() { struct timeval tval; gettimeofday(&tval,NULL); return (tval.tv_sec * 1000000LL + tval.tv_usec); } char * str = "abcdefghijklmnopqrstuvwxyz"; void test1() { int doc_count = 40; int outer_field_count = 80; Json::Value common_info; int64_t start_time = getCurrentTime(); for(size_t i=0; i<doc_count; ++i) { Json::Value auc_info; for( size_t j=0 ; j<outer_field_count; ++j ) { auc_info.append(str); } common_info.append(auc_info); } int64_t end_time = getCurrentTime(); cout << "append time: " << end_time - start_time << endl; } void test2() { int doc_count = 40; int outer_field_count = 80; Json::Value common_info; int64_t start_time = getCurrentTime(); Json::Value auc_info; for(size_t i=0; i<doc_count; ++i) { for( size_t j=0 ; j<outer_field_count; ++j ) { auc_info[j] = str; } common_info.append(auc_info); } int64_t end_time = getCurrentTime(); cout << "opt append time: " << end_time - start_time << endl; } void test3() { int doc_count = 40; int outer_field_count = 80; Json::Value common_info; int64_t start_time = getCurrentTime(); Json::Value auc_info; for(size_t i=0; i<doc_count; ++i) { for( size_t j=0 ; j<outer_field_count; ++j ) { auc_info[j] = Json::StaticString(str); } common_info.append(auc_info); } int64_t end_time = getCurrentTime(); cout << "StaticString time: " << end_time - start_time << endl; } int main(int argc,const char *argv[]) { test1(); test2(); test3(); return 0; } 编译优化默认情况下,JsonCpp编译时并没有带优化参数,自己可以加上优化参数。Linux环境下在下面这段代码中的CCFLAGS加入”O2″。 elifplatform.startswith('linux-gcc'): 可以看到使用O2优化比默认编译的版本性能提升一倍多。 append time: 4946 使用方法上的优化测试代码中第三种方法比第一种方法效率提升了一倍多。第三种方法之所以效率更高,有两个原因。 1、首先是在循环中一直复用auc_info对象。第一个循环就能将auc_info的长度初始化为doc_count。通过下标的访问方法,一直复用数组中的元素。 2、如果key和value内存不会被释放,那么使用StaticString效率会更高,省去了构造CZString时拷贝的开销。 代码优化因为在JsonCpp中一切都是Value,所以会有大量的隐性类型转换,要构造大量的Value对象。为了提高性能,可以在实现绕过这个机制,牺牲一致性。 因为Value最常用的类型是字符串,因此给Value增加一个setValue函数。 void Value::setValue(constStaticString& value ) 再测试一下性能,可以发现性能较第三种方法还有提升。 最后还有一个办法就是静态链接。JsonCpp库本身非常小,将其静态链接能稍微提升一点性能。下面是静态链接时基准测试程序的耗时情况。 参考: http://www.searchtb.com/2012/11/jsoncpp-optimization.html http://outofmemory.cn/code-snippet/1546/c-usage-jsonCpp-process-json-data (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |