foreach + break vs linq FirstOrDefault performance difference

前端 未结 3 1157
生来不讨喜
生来不讨喜 2020-12-04 17:52

I have two classes that perform date date range data fetching for particular days.

public class IterationLookup
{
    private IList          


        
3条回答
  •  感动是毒
    2020-12-04 18:36

    Further to Gabe's answer, I can confirm that the difference appears to be caused by the cost of re-constructing the delegate for every call to GetPointData.

    If I add a single line to the GetPointData method in your IterationRangeLookupSingle class then it slows right down to the same crawling pace as LinqRangeLookupSingle. Try it:

    // in IterationRangeLookupSingle
    public TItem GetPointData(DateTime point)
    {
        // just a single line, this delegate is never used
        Func dummy = i => i.IsWithinRange(point);
    
        // the rest of the method remains exactly the same as before
        // ...
    }
    

    (I'm not sure why the compiler and/or jitter can't just ignore the superfluous delegate that I added above. Obviously, the delegate is necessary in your LinqRangeLookupSingle class.)

    One possible workaround is to compose the predicate in LinqRangeLookupSingle so that point is passed to it as an argument. This means that the delegate only needs to be constructed once, not every time the GetPointData method is called. For example, the following change will speed up the LINQ version so that it's pretty much comparable with the foreach version:

    // in LinqRangeLookupSingle
    public TItem GetPointData(DateTime point)
    {
        Func> builder = x => y => y.IsWithinRange(x);
        Func predicate = builder(point);
    
        return this.items.FirstOrDefault(predicate);
    }
    

提交回复
热议问题