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

Avoid a hash key generation and lookup when inserting in the LockingMechanism #18243

Open
wants to merge 2 commits into
base: contrib
Choose a base branch
from

Conversation

Henr1k80
Copy link
Contributor

@Henr1k80 Henr1k80 commented Feb 5, 2025

When writing to a dictionary, the hash has to be generated again, the bucket has to be looked up and searched for possible existing value. (exact same work for TryGetValue)

By getting a reference to any newly created value, this work is not needed, and the reference can simply be assigned the new value, without any hash generation, bucket lookup and searching.

This is a little change, to check if this kind of code is deemed acceptable.
This can be improved in a lot of places.

I would like to know the balance between having performing code and still have contributors reviewing.
Should everything be readable by graduates, even private stuff?
Are you allowed to add one extra line for performance, proven, but probably negligible?
Is there a process or tag for performance/new language features, or are you mostly geared for handling new features & fixing bugs?

Prerequisites

  • I have added steps to test this contribution in the description below

Copy link

github-actions bot commented Feb 5, 2025

Hi there @Henr1k80, thank you for this contribution! 👍

While we wait for one of the Core Collaborators team to have a look at your work, we wanted to let you know about that we have a checklist for some of the things we will consider during review:

  • It's clear what problem this is solving, there's a connected issue or a description of what the changes do and how to test them
  • The automated tests all pass (see "Checks" tab on this PR)
  • The level of security for this contribution is the same or improved
  • The level of performance for this contribution is the same or improved
  • Avoids creating breaking changes; note that behavioral changes might also be perceived as breaking
  • If this is a new feature, Umbraco HQ provided guidance on the implementation beforehand
  • 💡 The contribution looks original and the contributor is presumably allowed to share it

Don't worry if you got something wrong. We like to think of a pull request as the start of a conversation, we're happy to provide guidance on improving your contribution.

If you realize that you might want to make some changes then you can do that by adding new commits to the branch you created for this work and pushing new commits. They should then automatically show up as updates to this pull request.

Thanks, from your friendly Umbraco GitHub bot 🤖 🙂

{
// Since we've already checked that we're the parent in the WriteLockInner method, we don't need to check again.
// If it's the very first time a lock has been requested the WriteLocks dict hasn't been instantiated yet.
locks ??= new Dictionary<Guid, Dictionary<int, int>>();

// Try and get the dict associated with the scope id.
var locksDictFound = locks.TryGetValue(instanceId, out Dictionary<int, int>? locksDict);
ref Dictionary<int, int>? locksDict = ref CollectionsMarshal.GetValueRefOrAddDefault(locks, instanceId, out bool locksDictFound);
Copy link
Contributor

@AndyButland AndyButland Feb 6, 2025

Choose a reason for hiding this comment

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

This'll be quite a large comment on one line, but it's a good a place as any to trigger a discussion on the pros and cons of these types of changes!

So on the one had we need to be careful about these sort of "micro-optimisations". We have a lot of eyes on the code, both from HQ and even more from the community, so I do want to be careful we don't make things more obscure, and perhaps make it less accessible for contributions, without a non-negligible benefit. If you were scanning this function here, you might find it a bit harder now to understand what it's doing. Happy to confess I'd never come across the CollectionsMarshal call you'd used here, so I would have had to look it up to see what it was doing.

So perhaps we could look at these changes only for situation where:

  • We're on "hot path", where an optimisation, even if small, will be valuable.
  • We've considered and discounted any side-effects.
  • We add a comment justifying why we are using this code construct... something like:
// We are retrieving the inner dictionary via CollectionsMarshal.GetValueRefOrAddDefault over locks.TryGetValue here
// for improved performance, as this code is called often from the backoffice as operations are made.
// It's safe to do so as items are not added to or removed from the locks dictionary while the ref value is in use.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @AndyButland, regarding "hot path", the issue for me is that I would spend more time analyzing if it is a hot path, than just changing the code.
So for me, it would take less time to just do it everywhere possible.

Copy link
Member

Choose a reason for hiding this comment

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

I have to agree with Andy here, it is really nice to have an optimized app but we do want to know that it matters.

I would spend more time analyzing if it is a hot path

I think that's exactly what we'd like to see 🙈 I understand you love to implement the optimizations, but maintainability is a crucial part for us as well.

In the past we've often asked people who want to do many of these optimizations to also include tests that show the level of improvement (I saw you did that in a different PR as well).

I fully agree with adding a good comment above code that's optimized like this, as it's completely unreadable to me as a proficient but not expert C# programmer. Knowing what code was replaced here in the comment will allow me to understand the new code better. Of course I could try and do a git blame but that's a lot of extra overhead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Understandable, I will do some analysis before and comment, if I do more of these types of changes.

I have added comments, is it acceptable now?

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.

3 participants