这可能是一个愚蠢的问题,基于std :: set <>已经有完美的比较运算符的事实,但我想我可能会对我的特定用例进行优化,并且要确保我没有伤害到自己不知何故。“展平”std :: set <std::string>用于存储和比较?
基本上,我有一个昂贵的操作,需要输入std :: set &。我缓存操作的结果,这样我就可以返回的结果,如果相同的输入已经在过去。这确实需要存储套复印件(我做的
std::map<std::set<std::string>, Result*>
,然后每次调用操作时都要搜索一次,因为很可能连续调用同一个操作数千次,所以我会说缓存的std :: set在99%以上的时间内找到了。最近,我根据传入字符串中某些字符无效的事实,尝试了一些我认为可能的小改进:我将std :: set压扁成单个字符串,组件字符串用':'分隔。 '字符,然后我的std :: map变成
std::map<std::string, Result*>
并且每次调用该操作时,都会将该集合展平并在缓存中搜索单个字符串。
我实际上对性能改进感到惊讶。我的测试运行使用包含5个字符串的std :: sets,每个字符串长30个字符,并且运行10,000,000次搜索。在我的工作站,每次运行的时间分别为
std::map<std::set<std::string>, Result*> : 138.8 seconds
std::map<std::string, Result> : 89.2 seconds
看来,即使压扁设定每次调用的开销,第二种方法是一个巨大的进步。我想我的问题是:为什么?我在这里做了一些可能不好的事情,那就是有目的地避免了std :: set的实现者(即可能导致较大字符串导致坏堆碎片?)是因为集合中的单个字符串位于不同位置并且必须单独进行比较?我在脚下开枪自杀吗?在这种特殊情况下,这似乎是一个明显的改进,以提高性能。
如果你调用具有相同参数的时间功能99%,那么我会说有一个与主叫方,而不是与温控功能本身有问题。无论如何,你不能为你的集合添加某种'id',这样该方法只需要比较'id'而不是整个'set'?这听起来像你正在传递的设置不经常改变。 – user463035818
我没有简化一点,该函数的输入是std :: set和2个独立的消息进行比较。该集合描述了在比较之前应用于消息的转换,并且它构建了这种转换,这是昂贵的部分(应用它是微不足道的)。该集合几乎总是不变,但消息几乎总是不同的。理想情况下,我会让调用者以某种方式获得转换的句柄,然后在调用比较时使用句柄而不是该集合 - 不幸的是,这需要成为现有代码的简单替换。 – Kevin
只要确保你的分隔符不能成为实际字符串的一部分,你应该没问题。此外,每当性能不要忘记与std :: unordered_map或std :: unordered_set的bencmark。然而,字符串并不总是存储在其中的最佳类型,因为您必须读取整个字符串才能生成散列,而处理器<可以提前停止。 – SteakOverflow