无序地图比c ++中的地图慢吗?

时间:2014-03-05 13:34:21

标签: c++ stl

我正在使用带有map<long, X>的地图 为了调整性能,我决定尝试无序地图。 我用两个operator[]尝试了100k插入。 地图花了大约140秒,而无序地图工具大约需要230秒才能获得相同的代码。 我期待unordered_map更快!我错了还是在这里有点可疑?

已搜索过以前的答案,但他们都指出unordered_map更快。因此问题。可以提供更多细节。通过以下基准测试,第一种情况需要约0秒,第二种情况需要8秒。

#include <map>
#include <unordered_map>
#include <iostream>
#include <time.h>
#include <stdlib.h>

using namespace std;

struct X{
   long a, b, c, d, e, f;
   string x, y, z;
};

struct mapZ{
   long id;
   map<long, X> xMap;
};

struct unmapZ{
   long id;
   unordered_map<long, X> xUnMap;
};

unmapZ & addUnMap(unmapZ & um, X & xtmp)
{
    um.xUnMap[xtmp.a] = xtmp;
    return(um);
}

mapZ & addMap(mapZ & mp, X & xtmp)
{
    mp.xMap[xtmp.a] = xtmp;
    return(mp);
}

int main()
{
    int numItr = 10000;
    map<long, X> myMap;
    unordered_map<long, X> myUnMap;
    mapZ mp;
    unmapZ uz;
    uz.id = (long)1;
    uz.xUnMap = myUnMap;
    mp.id = (long)1;
    mp.xMap = myMap;

    time_t start = time(0);

    for(int i = 0; i < numItr; i++)
    {
        long id = (long)rand();
        X tmp;
        tmp.a = id; tmp.b = id; tmp.c = id; tmp.d = id; tmp.e=id; tmp.f=id;
        tmp.x = "ABCDEF"; tmp.y = "WXYZS"; tmp.z = "UVGHJ";
        mp = addMap(mp, tmp);
    }
    cout << "size of map: " << mp.xMap.size() << "\n";
    time_t eof_map = time(0);

    for(int i = 0; i < numItr; i++)
    {
        long id = (long)rand();
        X tmp;
        tmp.a = id; tmp.b = id; tmp.c = id; tmp.d = id; tmp.e=id; tmp.f=id;
        tmp.x = "ABCDEF"; tmp.y = "WXYZS"; tmp.z = "UVGHJ";
        uz = addUnMap(uz, tmp);
    }

    cout << "size of unmap: " << uz.xUnMap.size() << "\n";
    time_t eof_unmap = time(0);

    cout << "Map inset time: " << eof_map - start << "\n";
    cout << "Unord Map insert time: " << eof_unmap - eof_map << "\n";
    return(0);
   }

以下是运行基准测试的命令行:

g++ -O3 -std=c++0x -m64 -Wno-write-strings -fopenmp mapTest.cpp

在Ubuntu上运行GCC 4.6。

2 个答案:

答案 0 :(得分:4)

此基准代码存在许多问题,导致其输出无关紧要。

首先,你使用了一个完全不可靠和可怕的时钟。使用std :: high_performance_clock。

其次,您已经使用许多额外的std :: strings填充了示例值类型,并且您可以在任何地方复制此类型。内存分配器的高度可变性(以及您从非新鲜进程中不公平地运行一个测试的事实)非常糟糕。

第三,你在基准时间内包含了I / O之类的东西 - 不,当你输出相同的字符串时,它仍然完全不公平。

第四,rand()只能生成一小部分值,这是unordered_map的不公平比较。如果你的用例实际上只是一小部分值,你可以通过适当的更改来更好地推出哈希映射。

但是这里的鲸鱼是你的测试是不公平的,因为你是自我分配的。您已将地图和无序地图分配给自己。这是一个不公平的测试,因为遗留的map代码在其中进行了自我分配检查,使分配成为无操作。新的unordered_map代码遵循新的最佳实践,但没有。实际上,您冗余地复制了unordered_map 而只复制了unordered_map 数千次,只是为了好玩,将O(n)更改为O(n ^ 2)或O(n ^ 3)。当然,没有人会有任何理智的自我分配,所以这完全打破了所有相关的结果。

答案 1 :(得分:3)

这取决于您的密钥的确切值,以及您使用的查找模式。但是,在随机访问使用的或多或少均匀分布的密钥上,std::unordered_map查找和插入应该比std::map快得多。

我可以在GCC 4.8上重现你的结果,但不能在Clang 3.4上重现你的结果。差异足够大,即使是偏斜的基准测试也不应该产生那么大的差异:std::unordered_mapstd::map慢几个数量级。这可能是GCC c ++ stdlib实现中的一个错误,或者是g ++'优化器中的错误 - 尽管它可能仍然是基准测试的假象 - 评估这些差异的更好的微基准工具是Nonius