std__map,std__unordered_map,protobuf__map之间的性能比较
简单比较下 std::map、std::unordered_map 和 protobuf::Map 的性能,主要关注在 插入、查找 和 删除 操作上的效率以及内存管理的差异。
std::map
- 底层实现:std::map 使用红黑树作为底层数据结构,红黑树是一种平衡二叉查找树的变体结构,它的左右子树的高度差有可能会大于 1。所以红黑树不是严格意义上的平衡二叉树AVL,但对之进行平衡的代价相对于AVL较低, 其平均统计性能要强于AVL。红黑树具有自动排序的功能,因此它使得map也具有按key排序的功能,因此在map中的元素排列都是有序的。在map中,红黑树的每个节点就代表一个元素,因此实现对map的增删改查,也就是相当于对红黑树的操作。对于这些操作的复杂度都为O(logn),复杂度即为红黑树的高度。
- 插入、查找、删除性能:由于是有序的,对于大数据量场景,树结构的操作时间更长。
- 内存管理:std::map 内存占用较高,因为红黑树的每个节点都需要额外的指针存储,且树的平衡机制需要更多的内存管理。
- 适用场景:显然std::map 适合需要数据有序存储的情况。
std::unordered_map
- 底层实现:std::unordered_map 使用哈希表(hash table)作为底层数据结构,平均操作时间复杂度为 O(1),但最差情况下可能退化到 O(n)。key值是无序的。
- 插入、查找、删除性能:在平均情况下,std::unordered_map 的性能通常优于 std::map,适合频繁的插入和查找操作。
- 内存管理:哈希表在空间分配上通常会预分配一部分空间,以减少重哈希和再分配的频率。不过当哈希碰撞较多时,内存消耗会增加。
- 适用场景:std::unordered_map 适合不关心顺序,但需要高效查找和插入操作的场景。
protobuf::Map
- 底层实现:protobuf::Map 的具体实现网上搜索不到,但基于官方的Protobuf 文档(https://protobuf.dev/reference/cpp/api-docs/google.protobuf.map/), std::unordered_map,使用了哈希表来实现。
- 插入、查找、删除性能:protobuf::Map 在 Protobuf 序列化、反序列化场景中的性能优于 std::map 和 std::unordered_map,因为它直接支持二进制序列化,减少了额外的序列化和转换成本。
- 内存管理:protobuf::Map 为序列化和反序列化进行内存管理优化,减少了 Protobuf 数据格式和 C++ 容器之间的冗余转换,因此在存储大数据集或频繁数据交换时,内存消耗更低。
- 适用场景: 相比 std::map 和 std::unordered_map,对于不在乎顺序的场景而言,protobuf::Map 与 std::unordered_map性能差不多,但考虑到序列化时间和内存占用,直接使用protobuf::Map可能会比较合适。
参考资料
- https://protobuf.dev/reference/cpp/api-docs/google.protobuf.map/
- https://stackoverflow.com/questions/3902644/choosing-between-stdmap-and-stdunordered-map
- https://www.geeksforgeeks.org/map-vs-unordered_map-c/
- https://medium.com/@yakupcengiz/comparing-std-map-and-std-unordered-map-in-c-92aa18c5dc39
- chatgpt answer: