jsoncpp 执行效率优化,非常规极限优化,适合linux下, 效率几乎提高50%以上

7 篇文章 0 订阅
5 篇文章 0 订阅

这是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_; 

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来输出也不错(不过要注意多线程的问题)。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值