C++ 为什么std::unordered_map很慢,我可以更有效地使用它来缓解这种情况吗?

C++ 为什么std::unordered_map很慢,我可以更有效地使用它来缓解这种情况吗?,c++,performance,c++11,caching,unordered-map,C++,Performance,C++11,Caching,Unordered Map,我最近发现了一件奇怪的事。使用计算Collatz序列长度的速度似乎比计算速度快2倍以上 注意:我确实从问题中得到了一些提示,我试图利用这些知识使std::unordered_map尽我所能地发挥作用(我使用了g++4.6,它确实比最新版本的g++表现得更好,并且我试图指定一个合理的初始存储桶数,使其完全等于映射必须包含的最大元素数) 相比之下,它几乎比没有缓存快17倍,比使用std::unordered_map快40倍 我做错了什么,或者这个容器有那么慢,为什么?能让它表现得更快吗?或者,哈希映

我最近发现了一件奇怪的事。使用计算Collatz序列长度的速度似乎比计算速度快2倍以上

注意:我确实从问题中得到了一些提示,我试图利用这些知识使
std::unordered_map
尽我所能地发挥作用(我使用了g++4.6,它确实比最新版本的g++表现得更好,并且我试图指定一个合理的初始存储桶数,使其完全等于映射必须包含的最大元素数)

相比之下,它几乎比没有缓存快17倍,比使用
std::unordered_map
快40倍

我做错了什么,或者这个容器有那么慢,为什么?能让它表现得更快吗?或者,哈希映射本质上是无效的,在高性能代码中应该尽可能避免

有问题的基准是:

#include <iostream>
#include <unordered_map>
#include <cstdint>
#include <ctime>

std::uint_fast16_t getCollatzLength(std::uint_fast64_t val) {
    static std::unordered_map <std::uint_fast64_t, std::uint_fast16_t> cache ({{1,1}}, 2168611);

    if(cache.count(val) == 0) {
        if(val%2 == 0)
            cache[val] = getCollatzLength(val/2) + 1;
        else
            cache[val] = getCollatzLength(3*val+1) + 1;
    }

    return cache[val];
}

int main()
{
    std::clock_t tStart = std::clock();

    std::uint_fast16_t largest = 0;
    for(int i = 1; i <= 999999; ++i) {
        auto cmax = getCollatzLength(i);
        if(cmax > largest)
            largest = cmax;
    }
    std::cout << largest << '\n';

    std::cout << "Time taken: " << (double)(std::clock() - tStart)/CLOCKS_PER_SEC << '\n';
}

输出所花费的时间:0.324586

标准库的映射实际上本质上是缓慢的(
std::map
,尤其是
std::unordered\u map
)。谷歌的钱德勒·卡鲁斯(Chandler Carruth)在他的文章中解释了这一点;简而言之:
std::unordered_map
是不友好的缓存,因为它使用链表作为存储桶


提到了一些高效的散列映射实现,请使用其中的一个。

@我是怎么做的,还是这个容器太慢了?为什么?
无序的散列映射
在很多情况下都非常慢。大多数情况下,
std::vector
是最快的容器。数据位置>其他所有内容。@WhiZTiM编辑了这个问题,现在更好了吗?如果你有复杂的问题,我为你感到难过,儿子,std::unordered_map返回大O(N)。你检查过实际值了吗?考虑到999999的一半大于65536,IMO使用uint_fast16_t缓存值是可疑的。链接的对话确实是一个值得观看的优秀视频。这家伙对性能问题的理解比绝大多数认为自己了解性能问题的人要深入得多。
#include <iostream>
#include <unordered_map>
#include <cstdint>
#include <ctime>

std::uint_fast16_t getCollatzLength(std::uint_fast64_t val) {
    std::uint_fast16_t length = 1;
    while(val != 1) {
        if(val%2 == 0)
            val /= 2;
        else
            val = 3*val + 1;
        ++length;
    }
    return length;
}

int main()
{
    std::clock_t tStart = std::clock();

    std::uint_fast16_t largest = 0;
    for(int i = 1; i <= 999999; ++i) {
        auto cmax = getCollatzLength(i);
        if(cmax > largest)
            largest = cmax;
    }
    std::cout << largest << '\n';

    std::cout << "Time taken: " << (double)(std::clock() - tStart)/CLOCKS_PER_SEC << '\n';
}