其他分享
首页 > 其他分享> > c – 为什么std :: unordered_map变慢,我可以更有效地使用它来缓解这种情况吗?

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

作者:互联网

我最近发现了一件奇怪的事情.似乎用no caching at all计算Collat​​z序列长度比using std::unordered_map to cache all elements快2倍.

注意我确实从问题Is gcc std::unordered_map implementation slow? If so – why?中得到​​了提示,我尝试使用这些知识使std :: unordered_map尽可能地执行(我使用g 4.6,它确实比g的最新版本表现更好,我试图指定声音初始桶数,我使它完全等于地图必须保持的最大元素数).

在比较中,using std::vector to cache a few elements几乎比没有缓存快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.761717

而根本没有缓存的基准:

#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';
}

输出所用时间:0.324586

解决方法:

实际上,标准库的映射本质上很慢(std :: map尤其是std :: unoredered_map).谷歌的Chandler Carruth在CppCon 2014 talk年解释了这一点;简而言之:std :: unordered_map对缓存不友好,因为它使用链表作为存储桶.

This SO question提到了一些有效的哈希映射实现 – 改为使用其中一个.

标签:unordered-map,c,c11,performance,caching
来源: https://codeday.me/bug/20191008/1870777.html