Reputation: 3462
I was wondering if someone can shed some light on how reflection and also Dynamic LINQ causes a performance hit on 'first time usage' vs 'subsequent usages'.
Below is a snippet of my test case. My intention was to run the query 10 times, each iteration with different input parameters. What I noticed that was the first iteration was always slow with Dynamic LINQ, but faster for subsequent runs.
My question isn't specific to Dynamic LINQ, but Reflection also. Is .Net caching something on first usage? (e.g. dynamic LINQ expression tress, reflection PropertyInfo) What if this was a multi-threaded application? Where/how is this cached? e.g. in some local context? local thread? in global context?
BTW, our front-end is a WebApi app... so I'm wondering if we would be able to make use of performance gains on subsequent web requests?
var sw = new Stopwatch();
for (var i = 1; i <= iterations; i++)
{
//--- Part 1: Setup filter inputs
// code removed for brevity (e.g. startDate, endDate, location, etc.)
//--- Part 2: Regular LINQ
elapsedTime = 0;
RunStandardLinq(sw, startDate, endDate, location, mrnIds, out expected, out elapsedTime);
elapsedTimeRegularLinq += elapsedTime;
//--- Part 3: Dynamic LINQ
elapsedTime = 0;
RunDynamicLinq(sw, startDate, endDate, location, mrnIdsString, out actual, out elapsedTime);
elapsedTimeDynamicLinq += elapsedTime;
}
Here are the LINQ queries
private void RunStandardLinq(Stopwatch sw, DateTime startDate, DateTime endDate, string location, string[] mrnIds,
out IEnumerable<Encounter> results, out double elapsedMilliseconds)
{
//--- Regular LINQ operations - must match the Dynamic LINQ
sw.Restart();
var resultsEnumerable = _sampleData
.Where(e => e.Admission.Date >= startDate)
.Where(e => e.Admission.Date < endDate)
.Where(e => e.Location == location)
.Where(e => mrnIds.Contains(e.PhnIdentifier.Id))
.OrderByDescending(e => e.PhnIdentifier.Code)
;
results = resultsEnumerable.ToList();
sw.Stop();
elapsedMilliseconds = sw.Elapsed.TotalMilliseconds;
}
private void RunDynamicLinq(Stopwatch sw, DateTime startDate, DateTime endDate, string location, string mrnIdsString,
out IEnumerable<Encounter> results, out double elapsedMilliseconds)
{
//--- Dynamic LINQ operations - must match the Regular LINQ
sw.Restart();
IEnumerable resultsEnumerable = DynamicQueryable.OrderBy(_sampleData
.Where(@"Admission.Date >= @0", startDate)
.Where(@"Admission.Date < @0", endDate)
.Where(string.Format(@"Location=""{0}""", location))
.Where(@"PhnIdentifier.Id in " + mrnIdsString),
"PhnIdentifier.Code descending");
results = resultsEnumerable.Cast<Encounter>().ToList();
sw.Stop();
elapsedMilliseconds = sw.Elapsed.TotalMilliseconds;
}
Upvotes: 2
Views: 1298
Reputation: 14251
See here:
Call site caching. A dynamic call site is a place in the code where you perform an operation like a + b or a.b() on dynamic objects. The DLR caches the characteristics of a and b (usually the types of these objects) and information about the operation. If such an operation has been performed previously, the DLR retrieves all the necessary information from the cache for fast dispatch.
Upvotes: 2