首页 > 代码库 > string insert 的性能分析

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] = \0;    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\n", 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\t%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. 如果需要拷贝,则尽量拷贝将小数据拷贝到大数据处,而不是相反。
     

string insert 的性能分析