Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance difference for iteration over all elements std::unordered_map vs std::map?

Tags:

c++

c++11

stl

I wanted to map data with pointer as the key. What container should I have chosen, map or unordered_map? There are multiple questions on stackoverflow for this topic but none of them covers the performance aspect when we need to iterate over all the key-value pairs.

std::map<classKey* , classData*> myMap;
std::unordered_map<classKey* , classData*> myUnorderedMap;

for (auto & iter : myMap) { //loop1
    display(iter.second);
}

for (auto & iter : myUnorderedMap) { //loop2
    display(iter.second);
}

loop1 vs loop2 which one gives better performance. Bench Mark Provided by @RetiredNinja

For size = 10,000,000 We get following benchmark results:

enter image description here

like image 778
nav_jan Avatar asked Jun 30 '19 14:06

nav_jan


People also ask

Is unordered_map always faster than map?

For the unordered_map + map , it takes 70 ms for unordered_map insertion and 80 ms for map insertion. So the hybrid implementation is 50 ms faster. We should think twice before we use the map . If you only need the data to be sorted in the final result of your program, a hybrid solution may be better.

What is the difference between std::map and std :: unordered_map?

std::map Internally store elements in a balanced BST. Therefore, elements will be stored in sorted order of keys. std::unordered_map store elements using hash table. Therefore, elements will not be stored in any sorted order.

Should I use map or unordered_map?

map is used to store elements as key,value pairs in sorted order. unordered_map is used to store elements as key,value pairs in non-sorted order.

Is unordered Map slow?

std::unordered_map is supposedly slow because it has fairly stringent iterator invalidation requirements. In my experience, unless you wring the most performance out of your code as you can, it's not a huge issue; it's generally faster than most casual implementations.


1 Answers

As you might expect, this depends heavily on the actual implementation of the standard library data structures. Therefore, this answer will be a bit more theoretical and less tied to any one implementation.

A std::map uses a balanced binary tree under the covers. This is why it has O(log(n)) insertion, deletion, and lookup. Iterating over it should be linear because you just have to do a depth-first traversal (which will require O(log(n)) memory in the form of stack space). The benefit of using a std::map for iteration is that you will iterate over the keys in sorted order and you will get that benefit "for free".

A std::unordered_map uses a hash table under the covers. This allows you to have an amortized constant time insertion, deletion, and lookup. If the implementation is not optimized for iterating, a naive approach would be to iterate over every bucket in the hash table. Since a good hash table (in theory) has exactly one element in 50% of the buckets and zero in the rest, this operation will also be linear. However, it will take more "wall clock time" than the same linear operation for a std::map. To get around this, some hash table implementations keep a side list of all of the elements for fast iterations. If this is the case, iterating on a std::unordered_map will be faster because you can't get much better than iterating over contiguous memory (still linear time though, obviously).

In the extremely unlikely case that you actually need to optimize to this level (instead of just being curious about the performance in theory), you likely have much bigger performance bottlenecks elsewhere in your code.

All of this ignores the oddity of keying off of a pointer value, but that's neither here nor there.

Sources for further reading:

GCC std::map implementation

GCC std::unordered_map implementation

How GCC std::unordered_map achieves fast iteration

like image 83
JimPri Avatar answered Oct 23 '22 07:10

JimPri