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

[Perf] Avoid locking of service creation in scope if possible #203

Closed
dadhi opened this issue Jan 2, 2020 · 3 comments · Fixed by #322
Closed

[Perf] Avoid locking of service creation in scope if possible #203

dadhi opened this issue Jan 2, 2020 · 3 comments · Fixed by #322
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed performance
Milestone

Comments

@dadhi
Copy link
Owner

dadhi commented Jan 2, 2020

The idea is the Scope is usually created per thread or logical execution flow,
so it should be the rare cases when service creation is done on other threads.

@dadhi dadhi added enhancement New feature or request performance labels Jan 2, 2020
@dadhi
Copy link
Owner Author

dadhi commented Jan 6, 2020

  • Removing lock is gaining ~15% of warmed up resolution in a single threaded case real-world benchmark - which is huge.

  • We can add the rule to skip locking if you know what you doing but it is still risky.

  • The other problem with locking that we entering it prior to dependencies creation thus prolonging the lock duration.

@dadhi dadhi added the help wanted Extra attention is needed label Jan 6, 2020
@dadhi
Copy link
Owner Author

dadhi commented Jan 8, 2020

Idea:

  • TryGet the entry first and if failed then
  • Create a var newEntry = new ImMapEntry<object>(NoItem);
  • AddOrKeep(factoryID, newEntry);
  • Get the entry and compare it to newEntry
  • if entry == newEntry then this thread won and may proceed with creating and setting the service without locking (!), otherwise the thread may SpinWait while (entry.Value == NoItem) SpinWait(++times);

Open questions:

  • What if another thread is failed - we need to signal somehow for the waiting threads or should we? Maybe we can just die or try-catch the creation of the service and set the value to new Failed(ex) or something to signal the other threads - how much will it cost - likely still less than locking?

@dadhi dadhi changed the title Avoid locking of service creation in scope when on the same thread Avoid locking of service creation in scope if possible Feb 2, 2020
@dadhi
Copy link
Owner Author

dadhi commented Jun 6, 2020

The other problem with locking that we entering it prior to dependencies creation thus prolonging the lock duration

I think that's the only safe thing to improve on.
For instance for the Interpretation we can do the following:

  1. Check if scoped service is created and then return it.
  2. Otherwise, check if the service expression is NewExpression (or the MethodCall..) and extract its parameters.
  3. Interpret all parameters and then do as usual: create a slot for service, lock on the slot entry, check under the lock if service is not yet created, interpret service with the parameter values interpreted earlier, exit the lock.

This way the lock will be of constant time - just a single constructor call with known argument values (assuming that constructor itself does not do a db backup or similar).
We may try to use a SpinWait here avoiding the context switch before going to full lock.

@dadhi dadhi self-assigned this Sep 20, 2020
@dadhi dadhi added this to the v4.5.0 milestone Sep 20, 2020
@dadhi dadhi linked a pull request Sep 20, 2020 that will close this issue
@dadhi dadhi changed the title Avoid locking of service creation in scope if possible [Perf] Avoid locking of service creation in scope if possible Oct 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed performance
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant