我需要映射常量大小的字符串,其中只包含字母数字值(A-Z,0-9,没有小写字母)到其他字符串。 unordered_map变得非常大(数千万个键),而映射的值来自几千个字符串的集合。在进行分析时,我发现大部分时间都花在将新值插入地图(operator [])中,并且清除地图需要很长时间。
std::unordered_map<std::string, std::string> hashMap;
while (...){
...
hashMap[key] = value; // ~50% of program time is spent here
...
}
hashMap.clear(); // Takes a very long time, at this point hashMap.size() > 20,000,000
我的想法是字符串分配/解除分配非常慢,以及散列和插入地图。 有什么建议可以优化吗?请记住,密钥大小是常量,其内容限制为一组36个字符,并且映射的值来自有限集。我愿意使用除strings和unordered_map之外的不同容器/数据类型。
根据Baum Mit Augen的建议,我将我的密钥类型更改为无符号long long并创建了将base 36转换为decimal的函数:
unsigned long long ConvertBase36(const char* num)
{
unsigned long long retVal = 0;
for (int i = 0; i < 12; i++)
{
unsigned int digit = 0;
char currChar = num[i];
if (currChar <= '9')
{
digit = currChar - '0';
}
else
{
digit = currChar - 'A' + 10;
}
retVal *= 36;
retVal += digit;
}
return retVal;
}
这给了我整个程序运行时间大约10%的改进。 然后我再次尝试使用unordered_map reserve函数来查看它是否有任何区别,但它没有。 尝试使用map而不是unordered_map确实差了大约10%,所以我还原了这个改变。 最后用unsigned int替换字符串值会使事情变得更快。
答案 0 :(得分:4)
两个不相关的建议,但都与std::unordered_map::reserve
相关。
首先,由于您的无序地图包含10M的元素,因此在插入时可能会有许多重新分配/重新进行。一开始,您可能希望保留10M的条目。
自
映射的值来自几千个字符串的集合
您应该能够将值本身存储在辅助unordered_set
中,并将其reserve
置于足够大的位置,以确保insert
上没有迭代器失效 - 请参阅{{ 3}}。
您的(主要)unordered_map
可以将string
映射到std::unordered_set::const_iterator
。
答案 1 :(得分:0)
对于如此大量的条目,您可能需要考虑使用哈希中的桶数。
对于初学者,您可以使用以下方法查询实现定义的值:
malloc/emalloc
然后你可以玩,看看哪个值产生最好的结果:
unordered_map<T, U> um; cout << um.bucket_count();