-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Optimize Microsoft.Extensions.Caching.Memory #111050
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
Conversation
|
Tagging subscribers to this area: @dotnet/area-extensions-caching |
src/libraries/Microsoft.Extensions.Caching.Memory/src/CacheEntry.cs
Outdated
Show resolved
Hide resolved
|
The main win here is not eagerly allocating the options lists, is that right? Plus using the list-specific iterator instead of IEnumerable-T/IEnumerator-T. Definitely worthwhile - however, I'm not a huge fan of exposing the naked field, even as |
|
Yes, the allocation savings come from on-demand allocation of options lists and avoiding an enumerator allocation each time when using options. And skipping options allocation entirely in
|
Since this is an private List<Whatever>? _foos;
public IList<Whatever> Foos => _foos ??= []; // lazy alloc
internal List<Whatever>? FoosDirect => _foos; // note never allocsThis adds a line of code, but is IMO significantly preferable to exposing the naked field. |
src/libraries/Microsoft.Extensions.Caching.Abstractions/src/DistributedCacheExtensions.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Caching.Abstractions/src/DistributedCacheEntryOptions.cs
Show resolved
Hide resolved
|
This should be ready for merging if there are no other concerns. |
| entry.AbsoluteExpirationRelativeToNow = options.AbsoluteExpirationRelativeToNow; | ||
| entry.SlidingExpiration = options.SlidingExpiration; | ||
| entry.Size = value.Length; | ||
| entry.Value = value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this use entry.Dispose() for parity with the change applied to MemoryCacheExtensions in this same PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In practice entry.Dispose() would be slightly more efficient, but have to use using because someone could enable TrackLinkedCacheEntries for the MemoryCache options passed to this class.
The only overload I changed for MemoryCacheExtensions.Set was the one that only set Value (which always succeeds), other more complex overloads could cause exceptions from validation checks and thus need using.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That raises complex questions about what the correct behaviour even is if an exception is thrown and we've only done half the work - could that result in us committing something incorrect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, until Value is set, the entry is incomplete and Dispose won't store it in cache. TrackLinkedCacheEntries logic still needs to run however, because it needs to restore the state changed by entry allocation.
src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryDistributedCache.cs
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs
Outdated
Show resolved
Hide resolved
mgravell
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me; added some commentary and questions, but nothing that looks like a hard blocker
src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs
Outdated
Show resolved
Hide resolved
|
I resolved the merge conflicts again, could this be merged? |
| { | ||
| return (TItem?)(cache.Get(key) ?? default(TItem)); | ||
| cache.TryGetValue(key, out object? value); | ||
| return value is null ? default : (TItem)value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe clearer?
return cache.TryGetValue(key, out object? value) && value is not null ? (TItem)value : default;
src/libraries/Microsoft.Extensions.Caching.Abstractions/src/MemoryCacheExtensions.cs
Show resolved
Hide resolved
|
/ba-g all unknown failures are DeadLetters. |
Remove some allocations and interface calls.