Created
November 28, 2015 18:22
-
-
Save justinvp/a09a27fb4560c8638d35 to your computer and use it in GitHub Desktop.
KeyedCollection<TKey,TItem> equivalent microbenchmark (avoiding enumerator allocations when enumerating Items internally)
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
using System; | |
using System.Collections.Generic; | |
using System.Collections.ObjectModel; | |
using System.Diagnostics; | |
class Program | |
{ | |
static void Main() | |
{ | |
const int size = 100; | |
var before = new Before(); | |
var after = new After(); | |
AddItems(before, size); | |
AddItems(after, size); | |
var sw = new Stopwatch(); | |
const int ITERS = 1000000; | |
while (true) | |
{ | |
Console.Write("A:"); | |
sw.Restart(); | |
for (int i = 0; i < ITERS; i++) | |
{ | |
before.Contains(int.MaxValue); | |
before.Contains(int.MaxValue); | |
before.Contains(int.MaxValue); | |
before.Contains(int.MaxValue); | |
before.Contains(int.MaxValue); | |
before.Contains(10); | |
before.Contains(10); | |
before.Contains(10); | |
before.Contains(10); | |
before.Contains(10); | |
} | |
var elapsedA = sw.Elapsed; | |
Console.WriteLine(elapsedA); | |
GC.Collect(); | |
GC.WaitForPendingFinalizers(); | |
GC.Collect(); | |
Console.Write("B:"); | |
sw.Restart(); | |
for (int i = 0; i < ITERS; i++) | |
{ | |
after.Contains(int.MaxValue); | |
after.Contains(int.MaxValue); | |
after.Contains(int.MaxValue); | |
after.Contains(int.MaxValue); | |
after.Contains(int.MaxValue); | |
after.Contains(10); | |
after.Contains(10); | |
after.Contains(10); | |
after.Contains(10); | |
after.Contains(10); | |
} | |
var elapsedB = sw.Elapsed; | |
Console.WriteLine(elapsedB); | |
GC.Collect(); | |
GC.WaitForPendingFinalizers(); | |
GC.Collect(); | |
Console.WriteLine("A/B : {0}", elapsedA.TotalMilliseconds / elapsedB.TotalMilliseconds); | |
Console.WriteLine("B/A : {0}", elapsedB.TotalMilliseconds / elapsedA.TotalMilliseconds); | |
Console.WriteLine("(A-B)/A : {0}", Math.Abs((elapsedA.TotalMilliseconds - elapsedB.TotalMilliseconds) / elapsedA.TotalMilliseconds)); | |
Console.WriteLine("(B-A)/B : {0}", Math.Abs((elapsedB.TotalMilliseconds - elapsedA.TotalMilliseconds) / elapsedB.TotalMilliseconds)); | |
Console.WriteLine(); | |
Console.ReadLine(); | |
} | |
} | |
static void AddItems(ICollection<int> collection, int size) | |
{ | |
for (int i = 1; i <= size; i++) | |
{ | |
collection.Add(i); | |
} | |
} | |
} | |
class Before : Before<int, int> | |
{ | |
protected override int GetKeyForItem(int item) | |
{ | |
return item; | |
} | |
} | |
class After : After<int, int> | |
{ | |
protected override int GetKeyForItem(int item) | |
{ | |
return item; | |
} | |
} | |
abstract class Before<TKey, TItem> : Collection<TItem> | |
{ | |
private readonly IEqualityComparer<TKey> _comparer = EqualityComparer<TKey>.Default; | |
public Before() { } | |
public bool Contains(TKey key) | |
{ | |
if (key == null) | |
throw new ArgumentNullException("key"); | |
foreach (TItem item in Items) | |
{ | |
if (_comparer.Equals(GetKeyForItem(item), key)) | |
return true; | |
} | |
return false; | |
} | |
protected abstract TKey GetKeyForItem(TItem item); | |
} | |
abstract class After<TKey, TItem> : Collection<TItem> | |
{ | |
private readonly IEqualityComparer<TKey> _comparer = EqualityComparer<TKey>.Default; | |
public After() : base(new List<TItem>()) { } | |
new private List<TItem> Items | |
{ | |
get { return (List<TItem>)base.Items; } | |
} | |
public bool Contains(TKey key) | |
{ | |
if (key == null) | |
throw new ArgumentNullException("key"); | |
foreach (TItem item in Items) | |
{ | |
if (_comparer.Equals(GetKeyForItem(item), key)) | |
return true; | |
} | |
return false; | |
} | |
protected abstract TKey GetKeyForItem(TItem item); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment