Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use DashMap instead of Mutex<HashSet> to reduce lock contention #1

Merged
merged 3 commits into from
May 12, 2020

Conversation

ahornby
Copy link
Contributor

@ahornby ahornby commented May 12, 2020

I found that in my multithreaded use case ArcIntern was heavily contended on the single mutex per interned type.

Switching from Mutex to DashMap reduced contention as DashMap shards the keys under a number of mutexes.

Benefits will obviously will depend on your use case, but for me the time spent in ArcIntern::new or ArcIntern::drop has been reduced to between half and one-third of the original time.

Copy link
Owner

@ryzhyk ryzhyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is beautiful, thank you so much for this contribution! Do you know, by any chance, how this PR affects the single-threaded performance?

m.insert(b);
p
let m = Self::get_state();
let b = m.entry(Arc::new(val)).or_insert(());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having to create an Arc here unconditionally seems suboptimal. I also notice that the entry API is gone in the latest dashmap (4.0rc). Do you know how to implement equivalent functionality there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't see a way to avoid the Arc creation without introducing a race, as the dashmap entry api needs the key to acquire the shard's mutex.

Looking at the dashmap 4.0 PR xacrimon/dashmap#81 there are quite a few features remaining to be implemented, of which one insert_if_not_exists_and_get sounds like it would be the equivalent operation. I think its likely it would return a guard similar to https://github.com/xacrimon/dashmap/blob/acrimon/experimental/src/lib.rs#L136.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is beautiful, thank you so much for this contribution! Do you know, by any chance, how this PR affects the single-threaded performance?

You're welcome. I think we probably hit the internment race the same week, thanks for the alternative crate!

I've not run any single threaded benchmarks. Going by the DashMap benchmark graphs it's probably ok:

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarifications! I plan to merge and publish this later today or tomorrow. I wanted to add a sequential performance test first.

PS. I think there is a way to further reduce contention by not taking a lock on each reference decrement, but I haven't had a chance to think this through yet.

Add a single-threaded test.
Document the DashMap-based API in README.md.
@ryzhyk
Copy link
Owner

ryzhyk commented May 12, 2020

I notice 15% drop in performance in a purely sequential test, but concurrent test goes 3x faster, so I think the use if dashmap is well justified.

@ryzhyk ryzhyk merged commit 2a81b5b into ryzhyk:master May 12, 2020
@ryzhyk
Copy link
Owner

ryzhyk commented May 12, 2020

I just published it on crates.io as v0.2

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants