C++ STL map插入效率优化

最近遇到日志队列记录每个客户端ID传送过来的日志,里面的数据量,多的时候非常庞大,从服务器再传到网页效率偶尔感觉较低,故从数据结构和网页Http协议上做了优化


里面最开始有个结构体,std::map<std::string clientID,logStruct logInfo>
用于存储每个客户端的总日志信息。这个Map里面存了大量的日志路径和其他的参数项
考虑优化该map

C++ STL Map模板类中除了 insert() 方法 还提供了 emplace() 和 emplace_hint() 成员函数,也可以实现向 map 容器中插入新的键值对。
实现相同的插入操作,都比 insert() 方法的效率高

关于这两个函数,做了一些验证
得出的结论是
当调用insert时,是将对象传递给insert,对象被拷贝到容器中,
而当我们使用emplace时,是将参数传递给构造函,emplace使用这些参数在容器管理的内存空间中直接构造元素

map容器的三种插入方式insert emplace emplace_hint效率对比,测试平台为X64 release

#include <iostream>
#include <map>
#include <string>

class testMapDemo
{
    
    
public:
    testMapDemo(int num) : num(num)
    {
    
    
        std::cout << "testMapDemo构造函数" << std::endl;
    }
    testMapDemo(const testMapDemo& other) : num(other.num)
    {
    
    
        std::cout << "testMapDemo拷贝构造函数" << std::endl;
    }
    testMapDemo(testMapDemo&& other) : num(other.num)
    {
    
    
        std::cout << "testMapDemo移动构造函数" << std::endl;
    }
private:
    int num;
};

int main()
{
    
    
    //创建空 map 容器
    std::map<std::string, testMapDemo>mymap;
    std::cout << "调用insert:" << std::endl;
    mymap.insert({
    
     "insert", testMapDemo(100) });
    //
    std::cout << "调用emplace:" << std::endl;
    mymap.emplace("emplace", 100);

    //
    std::cout << "调用emplace_hint:" << std::endl;
    mymap.emplace_hint(mymap.begin(), "emplace_hint", 100);
    return 0;
}

ecplace和emplace都是在内部构造。少了两次移动构造。
ecplace和emplace都是在内部构造。少了两次移动构造。都说移动构造可以忽略不记,比拷贝代价低很多,那我们修改下上面的代码,循环插入10万次 和100万次看下。

#include <iostream>
#include <map>
#include <string>
#include<time.h>

class testMapDemo
{
    
    
public:
    testMapDemo(int num) : num(num)
    {
    
    
        //std::cout << "testMapDemo构造函数" << std::endl;
    }
    testMapDemo(const testMapDemo& other) : num(other.num)
    {
    
    
        // std::cout << "testMapDemo拷贝构造函数" << std::endl;
    }
    testMapDemo(testMapDemo&& other) : num(other.num)
    {
    
    
        //std::cout << "testMapDemo移动构造函数" << std::endl;
    }
private:
    int num;
};

int main()
{
    
    
    int testTimes = 1000000;
    //计时
    clock_t start, end;
    start = clock();
    //创建空 map 容器
    std::map<std::string, testMapDemo>mymap_insert;

    for (int i = 0; i < testTimes; i++)
    {
    
    
        //模拟不同key插入
        std::string tempKey = "insert" + std::to_string(i);
        mymap_insert.insert({
    
     tempKey, testMapDemo(100) });
    }

    end = clock();
    double  insertTime = (double)(end - start);
    std::cout << "调用insert 100万次,时间:" << insertTime / CLOCKS_PER_SEC << std::endl;
    //
    //创建空 mymap_emplace 容器
    start = clock();
    std::map<std::string, testMapDemo>mymap_emplace;

    for (int i = 0; i < testTimes; i++)
    {
    
    
        //模拟不同key插入
        std::string tempKey = "insert" + std::to_string(i);
        mymap_emplace.emplace(tempKey, 100);
    }

    end = clock();
    insertTime = (double)(end - start);
    std::cout << "调用emplace 100万次,时间:" << insertTime / CLOCKS_PER_SEC << std::endl;
    //
    //创建空 mymap_emplace_hint 容器
    start = clock();
    std::map<std::string, testMapDemo>mymap_emplace_hint;

    for (int i = 0; i < testTimes; i++)
    {
    
    
        //模拟不同key插入
        std::string tempKey = "insert" + std::to_string(i);
        mymap_emplace_hint.emplace(tempKey, 100);
    }

    end = clock();
    insertTime = (double)(end - start) ;
    std::cout << "调用emplace_hint 100万次,时间:" << insertTime / CLOCKS_PER_SEC << std::endl;
    return 0;
}

在这里插入图片描述
在这里插入图片描述

因为emplace_hint是可以指定位置插入的。会改变数据原有的位置和调整,所以有时候时间可能因为内部调整会慢一些,但是比insert效率还是来的高

写在结尾:
值得一提的是,一开始踩过的坑
std::map的不管哪个方法会忽略重复key,而不是替换,std::map必须先找出来erase掉才能插入。
QT里的QMap会默认直接替换。

猜你喜欢

转载自blog.csdn.net/qq_40861091/article/details/121556059