zoukankan      html  css  js  c++  java
  • string insert 的性能分析

    有这样一个网络传输包。

    前端有个固定的包头,包含了后面传输body的长度信息。

    在有拷贝的前提下,我们选用什么性能比较高呢?
            方案一
            复用data_buffer string 将Header 头insert到data_buffer中,将大量的字符串后移定长。
            方案二
            将Header外化一个string,然后调用append函数,将data_buffer的字符拷贝到head的string中去。
            方案三
            分配内存,memcpy 过去。
            方案四
            不分配内存,利用栈空间(受限),memcpy过去。
            
            这四种方案那种的效率最高呢?我比较好奇,做了下实验(如无说明,已然-O2优化),测试代码参考
    #include <string>
    #include <stdio.h>
    #include "Utility.h"
    int load_file(const char* filename, char** content, size_t* content_len)
    {
        FILE* fp = fopen(filename, "r");
        if (!fp)
        {
            return -1;
        }
        fseek(fp, 0, SEEK_END);
        size_t len = ftell(fp);
        rewind(fp);
        char* buf = (char*)malloc(len + 1);
        if (!buf)
        {
            return -2;
        }
        fread(buf, sizeof(char), len, fp);
        buf[len] = '';
        fclose(fp);
        *content = buf;
        *content_len = len;
        return 0;
    }
    
    int main(int argc, const char *argv[])
    {
        char* content;
        const char* file_name = argv[1];
        uint32_t space = atoi(argv[2]);
        uint32_t insert = atoi(argv[3]);
        size_t len = 0;
        if (load_file(file_name, &content, &len) < 0)
        {
            printf("load %s failed
    ", file_name);
            return -1;
        }
        std::string raw_content(content, len);
        for (int i = 0; i < space - 1 ; i++)
        {
            raw_content.append(content, len);
        }
        char size_str[64];
        snprintf(size_str, sizeof(size_str), "%u	%u",
                 insert, raw_content.size());
        std::string final_content("cooooooo%dddd$%DDD123r423");
        {
          TimeEval timer(size_str);
          if(insert == 0 )
          {
             raw_content.insert(0, final_content);
          } if (insert == 1)
          {
             final_content.append(raw_content);
          }
          if (insert == 2)
          {
              char* buf = (char*)malloc(final_content.size() + raw_content.size() + 1);
              memcpy(buf, final_content.c_str(), final_content.size());
              memcpy(buf + final_content.size(), raw_content.c_str(), raw_content.size());
              free(buf);
          }
        }
        return 0;
    }

    性能测试显示

    可以看到在insert移动文本长度在k 级别以上时,其效率较拷贝的效率高得多。

    个人觉得原因有两个
    1)cache
          大数据如果已然cache住,往里面拷贝小数据比较快。
          如果生成两份大数据,往变量中拷贝,cache的可能性要小,程序的局部性变低。
    2)内存分配
         通过gcc的代码append 一个大数据,和insert一份小数据,append分配内存空间的可能性要大得多。

    由于涉及到内存分配,方案3的效率最低。

    方案1 和方案2 的性能差别应该以上由于方案二分配了大量的(标红处)内存空间,gcc的代码如下

    结论:
           1. 分配和空间拷贝数据是比较耗时的。在程序中应该尽量减少内存分配。
           2. 如果需要拷贝,则尽量拷贝将小数据拷贝到大数据处,而不是相反。
         
  • 相关阅读:
    Jenkins简明入门(三) -- Blue Ocean,让一切变得简单
    TeamForge使用指南
    Jenkins简明入门(二) -- 利用Jenkins完成Python程序的build、test、deployment
    谈谈Python中的decorator装饰器,如何更优雅的重用代码
    Jenkins简明入门(一) -- 安装
    Python CSV 超简明用法
    Intel CPU命名规则的简略解析
    ef core 2.1 利用Query Type查询视图
    asp.net core 开发环境自定义域名及端口
    ef core 使用include进行外键连接查询
  • 原文地址:https://www.cnblogs.com/westfly/p/4155955.html
Copyright © 2011-2022 走看看