Skip to content

Instantly share code, notes, and snippets.

@caleb-vear
Created October 3, 2010 01:49
Show Gist options
  • Select an option

  • Save caleb-vear/608184 to your computer and use it in GitHub Desktop.

Select an option

Save caleb-vear/608184 to your computer and use it in GitHub Desktop.
Testing cached delegate wireup Event Handler Performance with 1,000,000 iterations
Time to build handler cache 3 ms or 6,548 ticks
Completed 1,000,000 iterations in 7,434 ms
Average Time is 0 ms or 14 ticks
Press enter to exit
private void Apply(Type eventType, TDomainEvent domainEvent)
{
string expectedMethodName = "On" + eventType.Name.Substring(0, eventType.Name.Length - "Event".Length);
var methodInfo = GetType().GetMethod(expectedMethodName, BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { eventType }, null);
if (methodInfo == null)
throw new UnregisteredDomainEventException(string.Format("The requested domain event '{0}' is not registered in '{1}'", eventType.FullName, GetType().FullName));
methodInfo.Invoke(this, new object[] { domainEvent });
}
Testing basic reflection wireup Event Handler Performance with 1,000,000 iterations
Completed 1,000,000 iterations in 21,427 ms
Average Time is 0 ms or 39 ticks
Press enter to exit
private void Apply(Type eventType, TDomainEvent domainEvent)
{
Action<object, IDomainEvent> handler;
if (_registeredEvents.TryGetValue(eventType, out handler) == false)
throw new UnregisteredDomainEventException(string.Format("The requested domain event '{0}' is not registered in '{1}'", eventType.FullName, GetType().FullName));
handler(this, domainEvent);
}
public AbstractAggregateRoot()
{
_registeredEvents = EventHandlerMappings.GetHandlersFor(GetType());
_appliedEvents = new List<TDomainEvent>();
}
private void Apply(Type eventType, TDomainEvent domainEvent)
{
MethodInfo methodInfo;
if (_registeredEvents.TryGetValue(eventType, out methodInfo) == false)
throw new UnregisteredDomainEventException(string.Format("The requested domain event '{0}' is not registered in '{1}'", eventType.FullName, GetType().FullName));
methodInfo.Invoke(this, new object[] { domainEvent });
}
Testing cached reflection wireup Event Handler Performance with 1,000,000 iterations
Time to build handler cache 2 ms or 4,167 ticks
Completed 1,000,000 iterations in 15,798 ms
Average Time is 0 ms or 29 ticks
Press enter to exit
public static class EventHandlerMappings
{
private static readonly object handlerMapLock = new object();
private static Dictionary<Type, Dictionary<Type, Action<object, IDomainEvent>>> handlerMaps = new Dictionary<Type, Dictionary<Type, Action<object, IDomainEvent>>>();
public static void ClearHandlerCache()
{
lock (handlerMapLock)
handlerMaps.Clear();
}
public static IDictionary<Type, Action<object, IDomainEvent>> GetHandlersFor(Type t)
{
lock (handlerMapLock)
{
Dictionary<Type, Action<object, IDomainEvent>> result = null;
if (handlerMaps.TryGetValue(t, out result) == false)
{
result = AddHandlerMapFor(t);
handlerMaps.Add(t, result);
}
return result;
}
}
private static Dictionary<Type, Action<object, IDomainEvent>> AddHandlerMapFor(Type t)
{
Stopwatch watch = new Stopwatch();
watch.Start();
var handlerMethods = from method in t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
let parameters = method.GetParameters()
where method.Name.StartsWith("On")
&& parameters.Length == 1
&& typeof(IDomainEvent).IsAssignableFrom(parameters[0].ParameterType)
select new { EventType = parameters[0].ParameterType, Method = method };
var result = new Dictionary<Type, Action<object, IDomainEvent>>();
foreach (var handler in handlerMethods)
{
var genericParams = new Type[] { t, handler.EventType };
var actionType = typeof(Action<,>).MakeGenericType(genericParams);
var action = Delegate.CreateDelegate(actionType, handler.Method);
var createDelegateMethod = typeof(EventHandlerMappings).GetMethod("CreateHandlerInvokeDelegate", BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(genericParams);
result.Add(handler.EventType, (Action<object, IDomainEvent>)createDelegateMethod.Invoke(null, new object[] { action}));
};
watch.Stop();
Console.WriteLine("Time to build handler cache {0:#,0} ms or {1:#,0} ticks", watch.ElapsedMilliseconds, watch.ElapsedTicks);
return result;
}
private static Action<object, IDomainEvent> CreateHandlerInvokeDelegate<TEventSource, TEvent>(Action<TEventSource, TEvent> action)
{
return delegate(object obj, IDomainEvent e)
{
action((TEventSource)obj, (TEvent)e);
};
}
}
private void Apply(Type eventType, TDomainEvent domainEvent)
{
Action<TDomainEvent> handler;
if (!_registeredEvents.TryGetValue(eventType, out handler))
throw new UnregisteredDomainEventException(string.Format("The requested domain event '{0}' is not registered in '{1}'", eventType.FullName, GetType().FullName));
handler(domainEvent);
}
Testing Manual Wireup Event Handler Performance with 1,000,000 iterations
Completed 1,000,000 iterations in 10,463 ms
Average Time is 0 ms or 19 ticks
Press enter to exit
class Program
{
public const int Iterations = 1000000;
static void Main(string[] args)
{
Console.WriteLine("Testing Manual Wireup Event Handler Performance with {0:#,0} iterations", Iterations);
// Dry run so that the code is JITed before we test.
RunTest("Dry Run");
List<Account> accounts = new List<Account>(Iterations);
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < Iterations; i++)
accounts.Add(RunTest(string.Format("Account {0}", i)));
watch.Stop();
Console.WriteLine("Completed {0:#,0} iterations in {1:#,0} ms", Iterations, watch.ElapsedMilliseconds);
Console.WriteLine("Average Time is {0:#,0} ms or {1:#,0} ticks", watch.ElapsedMilliseconds / (double)Iterations, watch.ElapsedTicks / (double)Iterations);
Console.WriteLine("\nPress enter to exit");
Console.ReadLine();
}
private static Account RunTest(string accountName)
{
IEventProvider<IDomainEvent> account = new Account();
account.LoadFromHistory(new IDomainEvent[]
{
new AccountCreatedEvent(accountName),
new DepositEvent(1000),
new WithdrawEvent(300),
new WithdrawEvent(250),
new DepositEvent(35.90M),
new WithdrawEvent(10.80M)
});
return account as Account;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment