为什么矢量在一个测试中比地图快,而在另一个测试则不然
Why is vector faster than map in one test, but not the other?
我一直被告知矢量很快,在我多年的编程经验中,我从未见过任何与之相关的东西。我决定(提前优化和)编写一个关联类,它是一个围绕顺序容器(即::std::vector
)的薄包装器,并提供与::std::map
相同的接口
然而,在我对各种大小的POD类型(4到64字节)和std::strings
(计数从8000到2000不等)的测试中,对于几乎所有的测试,::std::map::find
都比我的::associative::find
快,通常快15%左右。我做了一个简短、自包含、正确(可编译)的例子,在视频中清楚地显示了这一点。我检查了MSVC9对::std::map::find
的实现,并确认它与我的vecfind
和::std::lower_bound
代码非常匹配,无法解释为什么::std::map::find
运行得更快,除了在Stack Overflow上的一次讨论,人们猜测二进制搜索方法在上次比较之前根本不会从矢量的位置中受益(不会使其更快),并且它需要::std::map
节点不需要的指针算法,从而使其更慢。
今天有人向我提出了挑战,并在ideone上提供了这段代码,当我测试时,它显示矢量的速度是原来的两倍多。
StackOverflow的编码人员想让我了解这个明显的差异吗?我已经研究了这两组代码,它们对我来说似乎很有用,但也许我对它们玩得太多是盲目的。
(脚注:这与我之前的一个问题非常接近,但我的代码有几个错误得到了解决。由于新的信息/代码,我觉得这已经足够不同了,可以证明单独的问题是合理的。如果没有,我将努力合并它们。)
是什么让你认为mapfind()
比vecfind()
快?
代码的视频输出报告mapfind()
的滴答声比vecfind()
的滴答声多50%。在这里运行代码(x86_64-linux,g++-4.5.1),mapfind()
的时间大约是vecfind()
的两倍。
将地图/矢量放大10倍,差异将增加到约3倍。
然而,请注意,第二分量的总和是不同的。映射只包含一个具有任何给定第一个组件的对(使用我的本地PRNG,它创建了一个短两个元素的映射),而vector
可以包含多个这样的对。
您放入测试容器中的元素数量超过了Microsoft中rand()
可能输出的数量,因此您会得到重复的数字。排序后的矢量将包含所有这些,而map
将抛出重复项。填充后检查尺寸-矢量将有100000个元素,映射32768。由于地图要短得多,它当然会有更好的性能。
尝试使用multimap
进行苹果与苹果的比较。
我发现代码(http://ideone.com/41iKt)。(ideone实际上显示vector
更快,但使用Visual Studio 11开发人员预览版的本地构建显示map
更快)。
首先,我移动了map变量,并用它初始化向量,以获得相同的元素排序和uniquing,然后我给lower_bound
一个自定义比较器,它只比较first
,因为这就是map要做的。在这些变化之后,Visual Studio 11显示,对于相同的100000个元素,矢量的速度更快(尽管视频时间没有显著变化)。http://ideone.com/b3OnH
随着test_size
减少到8映射仍然更快。这并不奇怪,因为这就是算法复杂性的工作方式,函数中所有真正描述运行时物质的常数都是小N。我必须将test_size
提高到2700左右,才能使向量在这个系统上达到偶数,然后领先于映射。
- 更好的数据局部性:矢量将所有数据连续存储在内存中
- 较小的内存占用:矢量不需要太多的记账数据(例如,没有树节点对象)
这两种影响是否重要取决于情景。有两个因素可能会产生重大影响:
数据类型
如果元素是像整数这样的基元类型,那么std::向量是一个优势。在这种情况下,局部性确实有帮助,因为搜索所需的所有数据都在内存中的一个连续位置。
如果元素是字符串,那么局部性并没有那么大帮助。连续向量内存现在只存储可能遍布堆的指针对象。
数据大小
如果std::矢量适合特定的缓存级别,但std::map不适合,那么std::向量将具有优势。这是,尤其是如果您一直对相同的数据重复测试。
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 为什么不;名字在地图上是按顺序排列的吗
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- 基于多个条件处理地图中的所有元素
- 尽管测试成功,CppUnit测试核心仍被丢弃.为什么
- 数据成员SFINAE的C++17测试:gcc vs clang
- 在C++中将矢量转换为嵌套地图
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 为什么二进制搜索在我的测试中不起作用
- 从父数组测试用例构造二叉树失败
- 试图对缓存进行跨步测试,但程序并没有结束
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- OpenGL在启用深度测试时不会丢弃我的碎片
- 为测试目标创建具有不同源文件夹的文件
- 在子目录中使用target_sources()命令时用于单元测试(qtest)的项目结构
- VC++本机单元测试,找不到调试符号
- 换位表导致测试失败(但在游戏中运行良好)
- 用于交叉编译和CMake的预处理器宏的单元测试
- 谷歌测试中的期望值存储在哪里
- 为什么矢量在一个测试中比地图快,而在另一个测试则不然