这可能是一个愚蠢的问题,因为 std::set<> 已经有完美的比较运算符,但我认为我可能有一种优化我的特定用例并确保我不会受到伤害的方法。
基本上,我有一个昂贵的操作,该操作以 std::set& 作为输入。我正在缓存操作的结果,所以如果已经传入相同的输入,则可以返回结果。这确实需要存储副本,我正在使用一个
每次调用操作时,集合都会被展开并在缓存中搜索单个字符串。
实际上,性能的提升让我感到惊讶。我的测试运行使用包含5个字符串(每个字符串长30个字符)的std::set,并运行了1000万次搜索。在我的工作站上,每次运行的时间如下:
看起来,即使每次调用时都要展开集合的开销,第二种方法也是一个巨大的改进。 我的问题是:为什么呢?我在这里做了一些潜在的不良行为吗,std::set的实现者故意避免了这些行为(即可能导致更大字符串的堆片段化)?这仅仅是因为集合中的单个字符串位于不同的位置并且必须分别进行比较吗? 我是否正自我毁灭? 在这种特定情况下,这似乎是一个太明显的改进,可以给出如此强的性能提升。
基本上,我有一个昂贵的操作,该操作以 std::set& 作为输入。我正在缓存操作的结果,所以如果已经传入相同的输入,则可以返回结果。这确实需要存储副本,我正在使用一个
std::map<std::set<std::string>, Result*>
每次调用操作时,都需要进行搜索。由于同一操作很可能会被连续调用数千次,所以缓存的std::set被发现的概率大于99%。最近我尝试了一个可能会带来小改进的实验,基于传入字符串中某些字符是无效的这个事实:我将std::set压缩成单个字符串,并使用“:”字符作为分隔符。我的std::map变成了
std::map<std::string, Result*>
每次调用操作时,集合都会被展开并在缓存中搜索单个字符串。
实际上,性能的提升让我感到惊讶。我的测试运行使用包含5个字符串(每个字符串长30个字符)的std::set,并运行了1000万次搜索。在我的工作站上,每次运行的时间如下:
std::map<std::set<std::string>, Result*> : 138.8 seconds
std::map<std::string, Result> : 89.2 seconds
看起来,即使每次调用时都要展开集合的开销,第二种方法也是一个巨大的改进。 我的问题是:为什么呢?我在这里做了一些潜在的不良行为吗,std::set的实现者故意避免了这些行为(即可能导致更大字符串的堆片段化)?这仅仅是因为集合中的单个字符串位于不同的位置并且必须分别进行比较吗? 我是否正自我毁灭? 在这种特定情况下,这似乎是一个太明显的改进,可以给出如此强的性能提升。
unordered_map
可能更有效率。此外,当使用字符串作为键时,如果不需要按字母顺序排序,先比较字符串长度可能更有效率。例如,将"z"排在"aa"之前。 - MSalters