unordered_map 查找数组的索引
unordered_map to find indices of an array
我想高效地查找集合的索引。我正在使用 unordered_map 并制作这样的逆向映射
std::unordered_map <int, int> myHash (size);
Int i = 0;
for (it = someSet.begin(); it != someSet.end(); it++)
{
myHash.insert({*it , i++});
}
有效但效率不高。我这样做是为了在需要索引时随时访问它们 O(1)。性能分析告诉我这部分成为我代码的热点。
VTune 告诉我 new
运算符是我的热点。我猜 unordered_map 里面发生了什么事。
在我看来,这个案子应该得到有效处理。我还没有找到好的方法。有更好的解决方案吗?一个正确的构造函数?
也许我应该将更多信息传递给构造函数。我查找了初始化列表,但这并不是我想要的。
更新:让我补充一些信息。集合并不那么重要;我将集合保存到一个数组中(已排序)。稍后我需要找到唯一值的索引。我可以在 logn 中完成,但速度不够快。这就是我决定使用哈希的原因。集合的大小(子矩阵的列)在此之后不会改变。
它源于稀疏矩阵计算,我需要在更大的矩阵中找到子矩阵的索引。因此,查找的大小和模式取决于输入矩阵。它适用于较小的问题。我可以使用查找 table,但是当我计划并行执行它时,每个线程的查找 table 可能很昂贵。我在创建时有哈希的确切大小。我想通过将它发送给构造函数它会停止重新分配。我真的不明白为什么要重新分配这么多。
std::unordered_map 通常被实现为好像它是
std::vector<std::list<std::par<int, int>>>
这会导致每个节点的大量分配和释放,每个(释放)分配都使用导致争用的锁。
您可以通过使用 emplace 而不是 insert 来帮助它一点,或者您可以跳入 pmr 分配器的奇妙新世界。如果您对 pmr::unordered_map 的创建和销毁是单线程的,您应该能够从中获得很多额外的性能。参见 Jason Turners C++ Weekly - Ep 222 - 3.5x Faster Standard Containers With PMR!,他的示例有点小,但您可以了解总体思路。
问题是,std::unordered_map
,主要实现为向量列表,非常 cache-unfriendly,并且在 keys/values(如 int,int
在你的情况下),更不用说需要大量的(重新)分配。
作为替代方案,您可以尝试 third-party 哈希映射实现 open addressing with linear probing (a mouthful, but the underlying structure is simply a vector, i.e. much more cache-friendly). For example, Google's dense_hash_map
or this: flat_hash_map
。两者都可以用作 unordered_map
的 drop-in 替代品,并且只需要另外指定一个 int
值作为“空”键。
我想高效地查找集合的索引。我正在使用 unordered_map 并制作这样的逆向映射
std::unordered_map <int, int> myHash (size);
Int i = 0;
for (it = someSet.begin(); it != someSet.end(); it++)
{
myHash.insert({*it , i++});
}
有效但效率不高。我这样做是为了在需要索引时随时访问它们 O(1)。性能分析告诉我这部分成为我代码的热点。
VTune 告诉我 new
运算符是我的热点。我猜 unordered_map 里面发生了什么事。
在我看来,这个案子应该得到有效处理。我还没有找到好的方法。有更好的解决方案吗?一个正确的构造函数?
也许我应该将更多信息传递给构造函数。我查找了初始化列表,但这并不是我想要的。
更新:让我补充一些信息。集合并不那么重要;我将集合保存到一个数组中(已排序)。稍后我需要找到唯一值的索引。我可以在 logn 中完成,但速度不够快。这就是我决定使用哈希的原因。集合的大小(子矩阵的列)在此之后不会改变。
它源于稀疏矩阵计算,我需要在更大的矩阵中找到子矩阵的索引。因此,查找的大小和模式取决于输入矩阵。它适用于较小的问题。我可以使用查找 table,但是当我计划并行执行它时,每个线程的查找 table 可能很昂贵。我在创建时有哈希的确切大小。我想通过将它发送给构造函数它会停止重新分配。我真的不明白为什么要重新分配这么多。
std::unordered_map
std::vector<std::list<std::par<int, int>>>
这会导致每个节点的大量分配和释放,每个(释放)分配都使用导致争用的锁。
您可以通过使用 emplace 而不是 insert 来帮助它一点,或者您可以跳入 pmr 分配器的奇妙新世界。如果您对 pmr::unordered_map 的创建和销毁是单线程的,您应该能够从中获得很多额外的性能。参见 Jason Turners C++ Weekly - Ep 222 - 3.5x Faster Standard Containers With PMR!,他的示例有点小,但您可以了解总体思路。
问题是,std::unordered_map
,主要实现为向量列表,非常 cache-unfriendly,并且在 keys/values(如 int,int
在你的情况下),更不用说需要大量的(重新)分配。
作为替代方案,您可以尝试 third-party 哈希映射实现 open addressing with linear probing (a mouthful, but the underlying structure is simply a vector, i.e. much more cache-friendly). For example, Google's dense_hash_map
or this: flat_hash_map
。两者都可以用作 unordered_map
的 drop-in 替代品,并且只需要另外指定一个 int
值作为“空”键。