Created
November 29, 2011 02:50
-
-
Save litera/1403144 to your computer and use it in GitHub Desktop.
Console application conparimg Lambda implementation performance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Program | |
{ | |
private static Random rnd = new Random(); | |
private const int RangeLength = 365; | |
private const int RangeCount = 1; | |
private const int MaxRangeLength = 100; | |
private const int IterationCount = 1000000; | |
private const int RepeatCount = 5; | |
private static readonly DateTime RangeStart = new DateTime(2012, 1, 1); | |
private static readonly DateTime RangeEnd = RangeStart.AddDays(RangeLength); | |
static void Main(string[] args) | |
{ | |
IList<RangeItem> items = GenerateRanges().ToList(); | |
RangeLookupBase<RangeItem> iter = new IterationRangeLookup<RangeItem>(RangeStart, RangeEnd, items); | |
RangeLookupBase<RangeItem> buil = new BuilderLambdaRangeLookup<RangeItem>(RangeStart, RangeEnd, items); | |
RangeLookupBase<RangeItem> norm = new NormalLambdaRangeLookup<RangeItem>(RangeStart, RangeEnd, items); | |
RangeLookupBase<RangeItem> prop = new ProperyClosureLambdaRangeLookup<RangeItem>(RangeStart, RangeStart, items); | |
RangeLookupBase<RangeItem> fiel = new FieldClosureLambdaRangeLookup<RangeItem>(RangeStart, RangeStart, items); | |
RangeLookupBase<RangeItem> cust = new CustomClosureLambdaRangeLookup<RangeItem>(RangeStart, RangeStart, items); | |
Console.Write("\nForeach loop".PadRight(25)); | |
for (int i = 0; i < RepeatCount; i++) | |
{ | |
Console.Write(" {0}ms", Execute(iter)); | |
} | |
Console.Write("\nFree variable".PadRight(25)); | |
for (int i = 0; i < RepeatCount; i++) | |
{ | |
Console.Write(" {0}ms", Execute(norm)); | |
} | |
Console.Write("\nClosure using property".PadRight(25)); | |
for (int i = 0; i < RepeatCount; i++) | |
{ | |
Console.Write(" {0}ms", Execute(prop)); | |
} | |
Console.Write("\nClosure using field".PadRight(25)); | |
for (int i = 0; i < RepeatCount; i++) | |
{ | |
Console.Write(" {0}ms", Execute(fiel)); | |
} | |
Console.Write("\nDouble method closure".PadRight(25)); | |
for (int i = 0; i < RepeatCount; i++) | |
{ | |
Console.Write(" {0}ms", Execute(cust)); | |
} | |
Console.Write("\nPredicate builder".PadRight(25)); | |
for (int i = 0; i < RepeatCount; i++) | |
{ | |
Console.Write(" {0}ms", Execute(buil)); | |
} | |
Console.WriteLine(""); | |
} | |
#region Execute | |
private static long Execute<TItem>(RangeLookupBase<TItem> lookup) | |
where TItem : RangeItem | |
{ | |
IList<TItem> result; | |
Stopwatch timer = new Stopwatch(); | |
timer.Start(); | |
for (int i = 0; i < IterationCount; i++) | |
{ | |
result = lookup.GetDayDataList(RangeStart.AddDays(rnd.Next(RangeLength))); | |
} | |
timer.Stop(); | |
return timer.ElapsedMilliseconds; | |
} | |
#endregion | |
#region GenerateRanges | |
/// <summary> | |
/// Generates an arbitarry number of random ranges. | |
/// </summary> | |
/// <returns>Returns a set of randomly generated ranges.</returns> | |
private static IEnumerable<RangeItem> GenerateRanges() | |
{ | |
int startOffset, endOffset; | |
for (int i = 0; i < RangeCount; i++) | |
{ | |
startOffset = rnd.Next(RangeLength - 10); | |
endOffset = startOffset + 1 + rnd.Next(Math.Min(RangeLength - startOffset, MaxRangeLength)); | |
yield return new RangeItem( | |
i, | |
RangeStart.AddDays(startOffset), | |
RangeStart.AddDays(endOffset) | |
); | |
} | |
} | |
#endregion | |
} | |
#region Utility classes | |
#region RangeItem | |
/// <summary> | |
/// A simple date range related entity. | |
/// </summary> | |
public class RangeItem | |
{ | |
public int Id { get; private set; } | |
public DateTime Start { get; private set; } | |
public DateTime End { get; private set; } | |
public int Length | |
{ | |
get { return (int)(this.End - this.Start).TotalDays; } | |
} | |
public RangeItem(DateTime start, DateTime end) : this(-1, start, end) { } | |
public RangeItem(int id, DateTime start, DateTime end) | |
{ | |
this.Id = id; | |
this.Start = start; | |
this.End = end; | |
} | |
/// <summary> | |
/// Checks whether provided day is within date range of this instance. | |
/// </summary> | |
/// <param name="day"> | |
/// <see cref="DateTime">DateTime</see> instance to check. | |
/// </param> | |
public bool IsDayWithinRange(DateTime day) | |
{ | |
return day >= this.Start && day < this.End; | |
} | |
} | |
#endregion | |
#region RangeLookupBase | |
public abstract class RangeLookupBase<TItem> : RangeItem | |
where TItem : RangeItem | |
{ | |
protected IEnumerable<TItem> items = null; | |
protected RangeLookupBase(DateTime start, DateTime end, IEnumerable<TItem> items) | |
: base(start, end) | |
{ | |
this.items = items; | |
} | |
public abstract IEnumerable<TItem> GetDayData(DateTime day); | |
public IList<TItem> GetDayDataList(DateTime day) | |
{ | |
return this.GetDayData(day).ToList(); | |
} | |
} | |
#endregion | |
#region IterationRangeLookup | |
public class IterationRangeLookup<TItem> : RangeLookupBase<TItem> | |
where TItem : RangeItem | |
{ | |
public IterationRangeLookup(DateTime start, DateTime end, IEnumerable<TItem> items) | |
: base(start, end, items) | |
{ | |
// does nothing else | |
} | |
public override IEnumerable<TItem> GetDayData(DateTime day) | |
{ | |
foreach (TItem item in this.items) | |
{ | |
if (item.IsDayWithinRange(day)) | |
{ | |
yield return item; | |
} | |
} | |
} | |
} | |
#endregion | |
#region BuilderLambdaRangeLookup | |
public class BuilderLambdaRangeLookup<TItem> : RangeLookupBase<TItem> | |
where TItem : RangeItem | |
{ | |
public BuilderLambdaRangeLookup(DateTime start, DateTime end, IEnumerable<TItem> items) | |
: base(start, end, items) | |
{ | |
// does nothing else | |
} | |
public override IEnumerable<TItem> GetDayData(DateTime day) | |
{ | |
Func<DateTime, Func<TItem, bool>> getPredicate = d => i => i.IsDayWithinRange(d); | |
return this.items.Where(getPredicate.Invoke(day)); | |
} | |
} | |
#endregion | |
#region NormalLambdaRangeLookup | |
public class NormalLambdaRangeLookup<TItem> : RangeLookupBase<TItem> | |
where TItem : RangeItem | |
{ | |
public NormalLambdaRangeLookup(DateTime start, DateTime end, IEnumerable<TItem> items) | |
: base(start, end, items) | |
{ | |
// does nothing else | |
} | |
public override IEnumerable<TItem> GetDayData(DateTime day) | |
{ | |
Func<TItem, bool> predicate = i => i.IsDayWithinRange(day); | |
return this.items.Where(predicate); | |
} | |
} | |
#endregion | |
#region ProperyClosureLambdaRangeLookup | |
public class ProperyClosureLambdaRangeLookup<TItem> : RangeLookupBase<TItem> | |
where TItem : RangeItem | |
{ | |
private class Closure<TObject, TVariable> | |
{ | |
public TVariable Variable { get; set; } | |
public Func<TObject, bool> Predicate { get; set; } | |
} | |
private Closure<TItem, DateTime> closure; | |
public ProperyClosureLambdaRangeLookup(DateTime start, DateTime end, IEnumerable<TItem> items) | |
: base(start, end, items) | |
{ | |
this.closure = new Closure<TItem, DateTime>(); | |
closure.Predicate = i => i.IsDayWithinRange(closure.Variable); | |
} | |
public override IEnumerable<TItem> GetDayData(DateTime day) | |
{ | |
this.closure.Variable = day; | |
return this.items.Where(this.closure.Predicate); | |
} | |
} | |
#endregion | |
#region FieldClosureLambdaRangeLookup | |
public class FieldClosureLambdaRangeLookup<TItem> : RangeLookupBase<TItem> | |
where TItem : RangeItem | |
{ | |
private class Closure<TObject, TVariable> | |
{ | |
public TVariable Variable; | |
public Func<TObject, bool> Predicate; | |
} | |
private Closure<TItem, DateTime> closure; | |
public FieldClosureLambdaRangeLookup(DateTime start, DateTime end, IEnumerable<TItem> items) | |
: base(start, end, items) | |
{ | |
this.closure = new Closure<TItem, DateTime>(); | |
this.closure.Predicate = i => i.IsDayWithinRange(this.closure.Variable); | |
} | |
public override IEnumerable<TItem> GetDayData(DateTime day) | |
{ | |
this.closure.Variable = day; | |
return this.items.Where(this.closure.Predicate); | |
} | |
} | |
#endregion | |
#region CustomClosureLambdaRangeLookup | |
public class CustomClosureLambdaRangeLookup<TItem> : RangeLookupBase<TItem> | |
where TItem : RangeItem | |
{ | |
public class Closure<TObject, TVariable> | |
{ | |
public TVariable Variable; | |
public Func<Closure<TObject, TVariable>, TObject, bool> OpenPredicate; | |
public bool ClosedPredicate(TObject o) | |
{ | |
return OpenPredicate(this, o); | |
} | |
} | |
private Closure<TItem, DateTime> closure; | |
public CustomClosureLambdaRangeLookup(DateTime start, DateTime end, IEnumerable<TItem> items) | |
: base(start, end, items) | |
{ | |
this.closure = new Closure<TItem, DateTime>() { | |
OpenPredicate = (closure, item) => item.IsDayWithinRange(closure.Variable) | |
}; | |
} | |
public override IEnumerable<TItem> GetDayData(DateTime day) | |
{ | |
this.closure.Variable = day; | |
return this.items.Where(this.closure.ClosedPredicate); | |
} | |
} | |
#endregion | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment