jsoncpp 执行效率优化,非常规极限优化,适合linux下, 效率几乎提高50%以上
2016-08-04 10:51
656 查看
这是2年多前, 一个游戏服务器项目要上线了,协议消息处理和数据存放都基本用json的,用的是jsoncpp开源库
主要逻辑处理部分是单线程处理,所以玩家一多cpu就吃不消了, 要优化,
用gprof等工具找啊找研究发现是 主要json部分引起的一些内存开销占用cpu资源过多。(还有一些智能指针,按下不表)
找了很多方法优化jsoncpp,
1.比如 http://www.2cto.com/kf/201211/172375.html
只优化了一些。
2.另外, Json::Value对象有个 swap接口,所有的 赋值操作能改 swap的都用swap(因为直接 = 赋值,会做一次对象拷贝)
3. 然后 数据嵌套的 基本不用append , 都用 Json::Value &one = jv_test[jv_test.size()]; 先取出来再赋值,这样就省了 append时的一次拷贝
4.StyledWriter尽量都变成 FastWriter的格式化
但改了好多代码,只是稍稍提高了点效率
5. 继续修改jsoncpp源码 把注释的处理代码去掉,好像用处也不大。
后来仔细看了一下jsoncpp代码, 发现 特别是writer里面, 有个字符串document_ 一直再 += , 拼接字符串,
原先代码 没用用一个统一的writer格式化, 很多都是用toStyledString()
std::string Value::toStyledString() const {
//StyledWriter writer;
FastWriter writer;
return writer.write(*this);
}
可想而知 这个document_ 这个字符串容器在 拼接字符串要分配多少次内存哈,不可想象。
如果改代码,量太大
就直接改底层的
一、writer.h里 注掉
//std::string document_;
二、json_writer.h里改一下代码
使用一个 线程级的 全局静态变量 替换 document_;
整体效率一下提高了50% - -!
reader也可以优化看看。
这个优化如果有需要可以拿去试试。 个人觉得全局 统一用一个writer来输出也不错(不过要注意多线程的问题)。
主要逻辑处理部分是单线程处理,所以玩家一多cpu就吃不消了, 要优化,
用gprof等工具找啊找研究发现是 主要json部分引起的一些内存开销占用cpu资源过多。(还有一些智能指针,按下不表)
找了很多方法优化jsoncpp,
1.比如 http://www.2cto.com/kf/201211/172375.html
只优化了一些。
2.另外, Json::Value对象有个 swap接口,所有的 赋值操作能改 swap的都用swap(因为直接 = 赋值,会做一次对象拷贝)
3. 然后 数据嵌套的 基本不用append , 都用 Json::Value &one = jv_test[jv_test.size()]; 先取出来再赋值,这样就省了 append时的一次拷贝
4.StyledWriter尽量都变成 FastWriter的格式化
但改了好多代码,只是稍稍提高了点效率
5. 继续修改jsoncpp源码 把注释的处理代码去掉,好像用处也不大。
后来仔细看了一下jsoncpp代码, 发现 特别是writer里面, 有个字符串document_ 一直再 += , 拼接字符串,
原先代码 没用用一个统一的writer格式化, 很多都是用toStyledString()
std::string Value::toStyledString() const {
//StyledWriter writer;
FastWriter writer;
return writer.write(*this);
}
可想而知 这个document_ 这个字符串容器在 拼接字符串要分配多少次内存哈,不可想象。
如果改代码,量太大
就直接改底层的
一、writer.h里 注掉
//std::string document_;
二、json_writer.h里改一下代码
使用一个 线程级的 全局静态变量 替换 document_;
std::string valueToQuotedString(const char *value, <strong>std::string* document</strong> /* = NULL*/) { if (value == NULL) return ""; // Not sure how to handle unicode... if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter(value)) {<strong> if(document != NULL) { std::string tmp = std::string("\"") + value + "\""; *document += tmp; return ""; } else { return std::string("\"") + value + "\""; }</strong> } // We have to walk value and escape any special characters. // Appending to std::string is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) std::string::size_type maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL std::string new_result; std::string* result = &new_result; if(document != NULL) { result = document; } else { (*result).reserve(maxsize); // to avoid lots of mallocs } (*result) += "\""; for (const char *c = value; *c != 0; ++c) { switch (*c) { case '\"': (*result) += "\\\""; break; case '\\': (*result) += "\\\\"; break; case '\b': (*result) += "\\b"; break; case '\f': (*result) += "\\f"; break; case '\n': (*result) += "\\n"; break; case '\r': (*result) += "\\r"; break; case '\t': (*result) += "\\t"; break; // case '/': // Even though \/ is considered a legal escape in JSON, a bare // slash is also legal, so I see no reason to escape it. // (I hope I am not misunderstanding something. // blep notes: actually escaping \/ may be useful in javascript to avoid </ // sequence. // Should add a flag to allow this compatibility mode and prevent this // sequence from occurring. default: if (isControlCharacter(*c)) { std::ostringstream oss; oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); (*result) += oss.str(); } else { (*result) += *c; } break; } } (*result) += "\""; return new_result; } <strong> //暂不考虑释放问题,如果线程不停创建使用,自动释放请参考http://www.searchtb.com/2012/09/tls.html static __thread std::string* jw_document_ = NULL; #define document_ (*jw_document_)</strong> // Class Writer // ////////////////////////////////////////////////////////////////// Writer::~Writer() {} // Class FastWriter // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false) { <strong> if(NULL == jw_document_) { jw_document_ = new std::string(); //printf("###FastWriter::FastWriter() new string()\n"); }</strong> } void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } std::string FastWriter::write(const Value &root) { <strong> document_.clear();</strong> writeValue(root); //document_ += "\n"; return document_; } void FastWriter::writeValue(const Value &value) { switch (value.type()) { case nullValue: if (!dropNullPlaceholders_) document_ += "null"; break; case intValue: document_ += valueToString(value.asLargestInt()); break; case uintValue: document_ += valueToString(value.asLargestUInt()); break; case realValue: document_ += valueToString(value.asDouble()); break; case stringValue:<strong> //document_ += valueToQuotedString(value.asCString()); valueToQuotedString(value.asCString(),&document_);</strong> break; case booleanValue: document_ += valueToString(value.asBool()); break; case arrayValue: { document_ += "["; int size = value.size(); for (int index = 0; index < size; ++index) { if (index > 0) document_ += ","; writeValue(value[index]); } document_ += "]"; } break; case objectValue: { document_ += "{"; Value::ObjectValues* value_map = value.getValueMap(); if(value_map != NULL) { Value::ObjectValues::iterator it = value_map->begin(); for ( Value::ObjectValues::iterator it = value_map->begin(); it != value_map->end(); ++it ) { if ( it != value_map->begin() ) document_ += ","; const char* name = it->first.c_str(); valueToQuotedString( name, &document_ ); document_ += yamlCompatiblityEnabled_ ? ": " : ":"; writeValue( it->second ); } } /* Value::Members members(value.getMemberNames()); document_ += "{"; for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) { const std::string &name = *it; if (it != members.begin()) document_ += ","; document_ += valueToQuotedString(name.c_str()); document_ += yamlCompatiblityEnabled_ ? ": " : ":"; writeValue(value[name]); } */ document_ += "}"; } break; }
整体效率一下提高了50% - -!
<strong>__thread </strong>是保证多线程下没有问题。
reader也可以优化看看。
这个优化如果有需要可以拿去试试。 个人觉得全局 统一用一个writer来输出也不错(不过要注意多线程的问题)。
相关文章推荐
- Linux的压缩及归档
- Linux下进入单用户模式,修改文件,密码
- linux mv命令
- kettle--window开发环境和linux运行环境的迁移
- Linux用户态和内核态之间的交互
- CentOS安装JDK1.8
- #9.DHCP服务器搭建
- linux下查看网关的命令/DNS
- centos 6.5 配置svn服务器
- Linux fsdisk添加sdc1
- linux cmake 升级
- UNIX/LINUX下C++程序计时方法
- Per-CPU变量
- CentOS下的Autoconf和AutoMake(完善篇) 3
- linux各种终端类型的区别和概念
- CentOS下的Autoconf和AutoMake(实践篇) 2
- linux route命令的使用详解
- centos7上安装influxdb
- (转帖整理)Linux下的Autoconf和AutoMake(理论篇) 1
- 【Linux】进程组、会话和精灵进程