反射和动态 LINQ 的性能 - 'first time' 对比 'subsequent runs'

Performance on Reflection and also Dynamic LINQ - 'first time' vs 'subsequent runs'

我想知道是否有人可以阐明反射和 Dynamic LINQ 如何导致 'first time usage' 与 'subsequent usages' 相比的性能下降。

下面是我的测试用例的片段。 我的意图是 运行 查询 10 次,每次迭代使用不同的输入参数。我注意到动态 LINQ 的第一次迭代总是很慢,但随后的 运行s.

更快

我的问题不是针对 Dynamic LINQ,而是针对 Reflection。 .Net 是否在首次使用时缓存某些内容? (例如动态 LINQ 表达式树、反射 PropertyInfo) 如果这是一个多线程应用程序怎么办? Where/how 这是缓存的吗?例如在某些当地情况下?本地线程?在全球范围内?

顺便说一句,我们的前端是一个 WebApi 应用程序...所以我想知道我们是否能够在后续的网络请求中利用性能提升?

    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;
    }

这是 LINQ 查询

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;
}

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.