文件搜索与C++内存容器搜索哪个更快?有无多键值保序容器?
两种OSM数据搜索方案速度对比
结论非常明确:不计入数据加载耗时的前提下,预加载到C++内存容器后再搜索的速度,远快于直接在磁盘文件上搜索,核心原因如下:
- 直接搜索磁盘文件的所有操作都绕不开磁盘IO开销:哪怕是提前拆分好的过滤后文件,每次检索都要从存储介质读取内容做匹配,普通SATA固态的随机访问延迟比内存高3个数量级,机械硬盘的差距更是达到4~5个数量级;就算是用内存映射(mmap)方式访问文件,未预读的内存页触发缺页中断时还是要走磁盘IO,速度远低于纯内存访问。如果需要多次搜索、或者文件体积较大,两者的速度差距可以达到几十到上千倍。
- 内存容器搜索是纯内存操作:数据已经完整驻留内存,根据搜索场景选择对应结构的容器,不管是逐行遍历匹配还是按键精准检索,都没有IO等待开销,单次检索耗时可以做到微秒甚至纳秒级。就算是和内存映射文件的全量扫描比,提前结构化存储到容器里的数据,内存访问局部性更好,缓存命中率更高,扫描速度也会快一大截。
可按插入顺序存储键值对的C++容器
分两类场景对应选择即可:
- 如果不需要按键快速查找,仅要求按插入顺序存储、遍历键值对:
直接用std::vector<std::pair<Key, Value>>就可以,天然严格遵循插入顺序,支持存储重复键,连续内存结构的遍历效率是所有容器里最高的。如果需要频繁在序列中间插入、删除元素,可以替换成std::list<std::pair<Key, Value>>,同样保证插入顺序。 - 如果需要支持按键快速检索,同时要求遍历顺序和插入顺序完全一致:
截止C++23版本,标准库没有原生提供满足该需求的容器,最轻量化的实现方式是自己做结构组合:用std::vector<std::pair<Key, Value>>按插入顺序在尾部存储实际键值对,再搭配std::unordered_map<Key, std::vector<size_t>>存储每个key对应在vector中的下标位置;插入时往vector尾部追加元素,同时更新哈希表的下标记录,查找时先通过哈希表拿到下标再访问vector内容,遍历直接走vector即可,性能和原生容器基本没有差距,也可以灵活支持重复键。
如果不想自己实现,也可以用成熟第三方库的现成组件:比如Boost库的boost::multi_index_container可以同时配置插入顺序索引、按键哈希/排序索引,不需要自己维护两套结构的一致性;不少常用开源库(比如nlohmann/json、spdlog)内部也自带了等价于JavaLinkedHashMap逻辑的ordered_map实现,开箱即用。
注意不要把按键排序的
std::map、std::flat_map和插入序容器搞混,这两个容器的遍历顺序是按key的大小排序的,和插入顺序无关;std::unordered_map是哈希表结构,标准不保证遍历顺序和插入顺序一致,不同STL实现的行为差异很大,不要依赖它的隐式顺序。
内容的提问来源于stack exchange,提问作者powerover9001
相关产品推荐
相关产品推荐

