Skip to content
This repository was archived by the owner on Nov 2, 2018. It is now read-only.

[Design]: Changes to improve performance #291

Closed
wants to merge 5 commits into from

Conversation

davidfowl
Copy link
Member

  • Track disposables in a list with lock instead of a concurrent bag
  • Allocate a single _createServiceAccessor instead of one per instance
  • Removed syncObject and just locked the _resolvedServices

Measurements on the way...

/cc @rynowak @halter73 @pranavkm @lodejard @benaadams

- Track disposables in a list with lock instead of a concurrent bag
- Allocate a single _createServiceAccessor instead of one per instance
- Removed syncObject and just locked the _resolvedServices
}
}

private object CaptureDisposable(object service)
{
// Skip capturing disposables for the root
if (_root == this)
Copy link
Member Author

Choose a reason for hiding this comment

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

Nobody disposes the root scope, an argument can be made that it is possible but the interface for the top level (IServiceProvider) requires a downcast to IDisposable to do so and that's pretty rare unless you're scoped. We can let the GC handle those objects.

@benaadams
Copy link
Contributor

This halves allocations for DI

vs

0

1

return value;
}

value = valueFactory(key, arg);
Copy link
Member

Choose a reason for hiding this comment

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

You can make this code a little clearer by getting rid of the while and changing the TryAdd to GetOrAdd(key, value). If your add fails, it's because someone was contending with you to also add a value and so you'll get the value they added.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Member Author

Choose a reason for hiding this comment

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

Feels like this is easier to read.

Copy link
Member

Choose a reason for hiding this comment

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

Follow your ❤️ - but this gives me the impression that it will run an arbitrary number of times, but it will only ever run 1.5 times at most.

@rynowak
Copy link
Member

rynowak commented Sep 16, 2015

overall looks good - main point here seems to be assuming that the service provider is low-contention and we can do simpler/lighter things because of that.

// This lets us pass a state parameter allocation free GetOrAdd
internal static TValue GetOrAdd<TKey, TValue, TArg>(this ConcurrentDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TArg, TValue> valueFactory, TArg arg)
{
if (dictionary == null)
Copy link
Contributor

Choose a reason for hiding this comment

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

If it's internal code, consider removing these exceptions and replacing it with Debug.Assert instead.

@benaadams
Copy link
Contributor

788k -> 384k (-51%)

If you didn't want to go full pooling, but were ok with partial pooling, you could pool the dictionary and list and clear them up in the disposable; which would trim it to 144k but limit the scope for the pooling.

788k -> 144k (-82%)

Though likely with that you'd need to return to an object for locking and add bool for dispose check

@davidfowl
Copy link
Member Author

updated.

Going to try a few more things:

  • Don't allocate disposables until required.
  • only capture transient objects in the list.

- Only use it for transient objects
- Use _resolvedServices as a lockObject to avoid allocating a lockObj
@davidfowl
Copy link
Member Author

@benaadams New changes for ya.

@pranavkm
Copy link
Contributor

Looks :shipit: to me. Will wait for @benaadams's numbers though.

@benaadams
Copy link
Contributor

Improved:

delayed-alloc

And down overall for the module/dll: 321k vs 401k on original PR so haven't put it back on somewhere else.

delayed-alloc

@davidfowl
Copy link
Member Author

Merged

@davidfowl davidfowl closed this Sep 16, 2015
@natemcmaster natemcmaster deleted the davidfowl/performance-proto branch November 2, 2018 16:24
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants