diff --git a/README.md b/README.md index c7b9b5f..36c6e87 100644 --- a/README.md +++ b/README.md @@ -208,10 +208,16 @@ Let's see what result we get for the insertion of random values from multiple th ![no_preselection](https://github.com/greg7mdp/parallel-hashmap/blob/master/img/no_preselection.PNG?raw=true) +If we were to do a intensive insertion test into a hash map from multiple threads, where we lock the whole hash table for each insertion, we would be likely to get even worse results than for a single threaded insert, because of heavy lock contention. +In this case, our expectation is that the finer grained locking of the parallel_hash_map (separate locks for each internal submap) will provide a speed benefit when compared to the single threaded insertion, and this is indeed what the benchmarks show: ![flat_par_mutex_4](https://github.com/greg7mdp/parallel-hashmap/blob/master/img/flat_par_mutex_4.PNG?raw=true) +If we increase the number of submaps, we should see more parallelism (less lock contention across threads, as the odds of two seperate threads inserting in the same subhash diminishes)m and this is indeed what we see: + + + ### In Conclusion We have seen that the novel parallel hashmap approach, used within a single thread, provides significant space advantages, with a very minimal time penalty. When used in a multi-thread context, the parallel hashmap still provides a significant space benefit, in addition to a consequential time benefit by drastically reducing (or even eliminating) lock contention when accessing the parallel hashmap. diff --git a/img/lock_various_sizes.PNG b/img/lock_various_sizes.PNG new file mode 100644 index 0000000..123c423 Binary files /dev/null and b/img/lock_various_sizes.PNG differ diff --git a/make_chart_data.py b/make_chart_data.py index 3179aac..4e8ebc1 100644 --- a/make_chart_data.py +++ b/make_chart_data.py @@ -44,14 +44,20 @@ proper_names = { 'std::unordered_map': 'std::unordered_map (1 thread)', 'absl::flat_hash_map': 'absl::flat_hash_map (1 thread)', 'absl::parallel_flat_hash_map': 'absl::parallel_flat_hash_map (1 thread)', - 'absl::parallel_flat_hash_map_mt': 'absl::parallel_flat_hash_map (8 threads)' + 'absl::parallel_flat_hash_map_mt': 'absl::parallel_flat_hash_map (8 threads)', + 'absl::parallel_flat_hash_map_4': 'absl::parallel_flat_hash_map (N=4, 8 threads)', + 'absl::parallel_flat_hash_map_5': 'absl::parallel_flat_hash_map (N=5, 8 threads)', + 'absl::parallel_flat_hash_map_6': 'absl::parallel_flat_hash_map (N=6, 8 threads)' } proper_color = { 'std::unordered_map': 0, 'absl::flat_hash_map': 1, 'absl::parallel_flat_hash_map': 2, - 'absl::parallel_flat_hash_map_mt': 2 + 'absl::parallel_flat_hash_map_mt': 2, + 'absl::parallel_flat_hash_map_4': 2, + 'absl::parallel_flat_hash_map_5': 3, + 'absl::parallel_flat_hash_map_6': 4 } bench_titles = { @@ -70,14 +76,19 @@ program_slugs = [ 'std::unordered_map', 'absl::flat_hash_map', 'absl::parallel_flat_hash_map', - 'absl::parallel_flat_hash_map_mt' + 'absl::parallel_flat_hash_map_mt', + 'absl::parallel_flat_hash_map_4', + 'absl::parallel_flat_hash_map_5', + 'absl::parallel_flat_hash_map_6' ] chart_data = {} for i, (benchtype, programs) in enumerate(by_benchtype.items()): chart_data[benchtype] = [] - for j, program in enumerate(programs): + k = programs.keys() + k.sort() + for program in k: data = programs.get(program, []) chart_data[benchtype].append({ 'label': proper_names[program], diff --git a/pdf/parallel_hashmap.html b/pdf/parallel_hashmap.html index 6326734..5fa85b5 100644 --- a/pdf/parallel_hashmap.html +++ b/pdf/parallel_hashmap.html @@ -270,6 +270,8 @@ class parallel_flat_hash_map;

Let's see what result we get for the insertion of random values from multiple threads, however this time we create a parallel_hash_map with internal locking, and modify the code so that each thread can insert values in any submap (no pre-selection).

no_preselection

+

If we were to do a intensive insertion test into a hash map from multiple threads, where we lock the whole hash table during each insertion, we would be likely to get even worse results than for a single threaded insert, because of heavy lock contention.

+

In this case, our expectation is that the finer grained locking of the parallel_hash_map (on internal submaps) will provide a speed benefit when compared to the single threaded insertion, and this is indeed what the benchmark shows:

flat_par_mutex_4

In Conclusion

We have seen that the novel parallel hashmap approach, used within a single thread, provides significant space advantages, with a very minimal time penalty. When used in a multi-thread context, the parallel hashmap still provides a significant space benefit, in addition to a consequential time benefit by drastically reducing (or even eliminating) lock contention when accessing the parallel hashmap.