我的自定义std::unordered_map使用非常缓慢

3

我正在尝试将图的一些信息存储在unordered_map中。每条边都有一些参数。总共有120条边,每条边有90 * 2个不同的参数。

我有以下std :: unordered_map <>的实现

typedef std::tuple<int, int, int, int> metric_tuple_key; // metric  tuple key


// define a hash function for this metric_tuple_key tuple
struct m_KeyHash : public std::unary_function<metric_tuple_key, std::size_t> {
        std::size_t operator()(const metric_tuple_key& k) const {
            // the magic operation below makes collisions less likely than just the standard XOR
            std::size_t seed = std::hash<int>()(std::get<0>(k));
            seed ^= std::hash<int>()(std::get<1>(k)) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
            seed ^= std::hash<int>()(std::get<2>(k)) + 0x9e3779b97f4a7c15 + (seed << 6) + (seed >> 2);
            return seed ^ (std::hash<char>()(std::get<3>(k)) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
        }
    };

// define the comparison operator for this  metric_tuple_key tuple
struct m_KeyEqual : public std::binary_function<metric_tuple_key, metric_tuple_key, bool> {
        bool operator()(const metric_tuple_key& v0, const metric_tuple_key& v1) const {
            return (std::get<0>(v0) == std::get<0>(v1) && std::get<1>(v0) == std::get<1>(v1) &&
                    std::get<2>(v0) == std::get<2>(v1) && std::get<3>(v0) == std::get<3>(v1));
        }
    };

std::unordered_map<metric_tuple_key, double, m_KeyHash, m_KeyEqual>           _metrics;

通过创建元组键,我能够将值插入到_metrics中。

现在,当指定一个键时,我想从_metrics获取一些值。

//Retrieve around 120  double values. Total number of entries in _metrics is 21600
double k = _metrics.at((std::make_tuple(m, k, edge.first, edge.second))). //do this 120 times

结果表明这非常慢(几乎需要400毫秒)。我希望它只需大约一毫秒或更少的时间。

我是否做错了什么,或者std::unordered_map不适用于我的用例。我以前使用python字典来解决相同的问题,并且在python字典中检索值几乎是瞬间完成的。

编辑:一些unordered_map统计信息:

 max_load_factor: 1

 size: 21600

 bucket_count: 25717

 load_factor: 0.839911

编辑:计时器代码:

#include <chrono>
#include <iostream>
#include <iomanip>

class Timer {
private:
    std::chrono::time_point<std::chrono::steady_clock> start , stop;;

public:

    void startClock();
    void stopClock();
    void elapsedTime(std::string &message);

};
#include "Timer.hpp"

void Timer::startClock() {
    start = std::chrono::steady_clock::now();
}

void Timer::stopClock() {
    stop = std::chrono::steady_clock::now();
}


void Timer::elapsedTime(std::string &message) {
    auto diff = stop - start;
    std::cout << "Elapsed time for " <<message<< " " << std::setprecision(13) <<std::chrono::duration <double, std::milli> (diff).count() << " ms" << std::endl;
}

而时间测量是:
T_met.startClock();
for (const auto& edges: list_of_arcs())
{
    double k = _metrics.at((std::make_tuple(m, k, edge.first, edge.second)))
}
T_met.stopClock();

很遗憾,我不熟悉这些术语。我会查一下并告诉你。 - Morpheus
您可以使用相关的成员函数从地图中获取这些指标。 - w08r
这是我的以前的代码。我已经将其更改为“int”,但结果并没有太大不同。 - Morpheus
你是如何测量时间的?在C++中对代码进行分析是非常微妙的。你应该解释一下你正在计时的内容和方式。 - alter_igel
1
为什么要定义自定义比较运算符?std::tuple提供的比较运算符有什么问题吗? - Daniel Langr
显示剩余13条评论
1个回答

2

搜索时间取决于哈希的质量。 你可以使用 "map" 进行测试 - 它具有稳定的搜索时间。 如果 map 比 unordered map 更快 - 说明你的哈希不好。


谢谢您的回复。我不确定我的哈希函数是否好用(我在问题中包含了它)。如果它不好用,我该如何改进呢? - Morpheus
我不知道如何改进你的哈希函数 :(。但是: - Evgeny
根据您的统计数据:您应该检查密钥哈希计算的持续时间。它可能稍微有点高。 - Evgeny
@Morpheus:你可以尝试使用boost::hash_combine来改进你的哈希函数,或者将你的元组更改为std::array<int, 4>并使用boost::hash,它有一个专门针对std::array的特化。 - sv90

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接