定时矢量与映射与未定义映射查找

Timed vector vs map vs unordered_map lookup

本文关键字:映射 查找 未定义 定时      更新时间:2023-10-16

我对矢量查找和地图查找很感兴趣,并为此编写了一个小测试程序。它似乎总是比我使用它更快。这里还有其他需要考虑的吗?测试有任何偏差吗?跑步的结果在底部。。它只需要几纳秒,但gcc在我的平台上似乎不支持它。

使用字符串进行查找当然会改变很多事情。

我使用的编译行是:g++-O3-std=c++0x-o查找.cpp

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <chrono>
#include <algorithm>
unsigned dummy = 0;
class A
{
public:
    A(unsigned id) : m_id(id){}
    unsigned id(){ return m_id; }
    void func()
    {
        //making sure its not optimized away
        dummy++;
    }
private:
    unsigned m_id;
};
class B
{
public:
    void func()
    {
        //making sure its not optimized away
        dummy++;
    }
};
int main()
{
    std::vector<A> v;
    std::unordered_map<unsigned, B> u;
    std::map<unsigned, B> m;
    unsigned elementCount = 1;
    struct Times
    {
        unsigned long long v;
        unsigned long long u;
        unsigned long long m;
    };
    std::map<unsigned, Times> timesMap;
    while(elementCount != 10000000)
    {
        elementCount *= 10;
        for(unsigned i = 0; i < elementCount; ++i)
        {
            v.emplace_back(A(i));
            u.insert(std::make_pair(i, B()));
            m.insert(std::make_pair(i, B()));
        }

        std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < elementCount; ++i)
        {
            auto findItr = std::find_if(std::begin(v), std::end(v),
                                        [&i](A & a){ return a.id() == i; });
            findItr->func();
        }
        auto tp0 = std::chrono::high_resolution_clock::now()- start;
        unsigned long long vTime = std::chrono::duration_cast<std::chrono::nanoseconds>(tp0).count();
        start = std::chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < elementCount; ++i)
        {
            u[i].func();
        }
        auto tp1 = std::chrono::high_resolution_clock::now()- start;
        unsigned long long uTime = std::chrono::duration_cast<std::chrono::nanoseconds>(tp1).count();
        start = std::chrono::high_resolution_clock::now();
        for(unsigned i = 0; i < elementCount; ++i)
        {
            m[i].func();
        }
        auto tp2 = std::chrono::high_resolution_clock::now()- start;
        unsigned long long mTime = std::chrono::duration_cast<std::chrono::nanoseconds>(tp2).count();
        timesMap.insert(std::make_pair(elementCount ,Times{vTime, uTime, mTime}));
    }
    for(auto & itr : timesMap)
    {
        std::cout << "Element count: " << itr.first << std::endl; 
        std::cout << "std::vector time:        " << itr.second.v << std::endl;
        std::cout << "std::unordered_map time: " << itr.second.u << std::endl;
        std::cout << "std::map time:           " << itr.second.m << std::endl;
        std::cout << "-----------------------------------" << std::endl;
    }
    std::cout << dummy;
}

./lookup 
Element count: 10
std::vector time:        0
std::unordered_map time: 0
std::map time:           1000
-----------------------------------
Element count: 100
std::vector time:        0
std::unordered_map time: 3000
std::map time:           13000
-----------------------------------
Element count: 1000
std::vector time:        2000
std::unordered_map time: 29000
std::map time:           138000
-----------------------------------
Element count: 10000
std::vector time:        22000
std::unordered_map time: 287000
std::map time:           1610000
-----------------------------------
Element count: 100000
std::vector time:        72000
std::unordered_map time: 1539000
std::map time:           8994000
-----------------------------------
Element count: 1000000
std::vector time:        746000
std::unordered_map time: 12654000
std::map time:           154060000
-----------------------------------
Element count: 10000000
std::vector time:        8001000
std::unordered_map time: 123608000
std::map time:           2279362000
-----------------------------------
33333330

我对测试得比其他任何东西都好的向量一点也不感到震惊。它的asm代码(实际的反汇编)分解如下(在我的Apple LLVM 4.2上完全选择):

0x100001205:  callq  0x100002696               ; symbol stub for: std::__1::chrono::steady_clock::now()
0x10000120a:  testl  %r13d, %r13d
0x10000120d:  leaq   -272(%rbp), %rbx
0x100001214:  je     0x100001224               ; main + 328 at main.cpp:78
0x100001216:  imull  $10, %r14d, %ecx
0x10000121a:  incl   7896(%rip)                ; dummy
0x100001220:  decl   %ecx
0x100001222:  jne    0x10000121a               ; main + 318 [inlined] A::func() at main.cpp:83
main + 318 at main.cpp:83
0x100001224:  movq   %rax, -280(%rbp)
0x10000122b:  callq  0x100002696               ; symbol stub for: std::__1::chrono::

注意"循环"(jne 0x10000121a)。"find_if"已经完全优化,其结果是使用递减寄存器对数组进行有效扫描,以计算全局增量的次数这就是正在做的一切;在这件事上没有进行任何形式的搜查

所以,是的,这就是你使用它的方式。

首先,您似乎不会在测试之间清除容器。所以它们不包含你认为的内容。

其次,根据你的时间,你的向量表现出线性时间,这是不可能的,因为你的算法的复杂性是O(N*N)。可能它被优化掉了。与其试图对抗优化,我建议关闭它

第三,你的值对于向量来说太可预测了。这可能会对其产生巨大影响。尝试随机值(或random_shuffle())