Skip to content

Instantly share code, notes, and snippets.

@Sergio0694
Created June 25, 2020 12:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sergio0694/f3e072845b01cd2e4e7e5fcc8c7a1156 to your computer and use it in GitHub Desktop.
Save Sergio0694/f3e072845b01cd2e4e7e5fcc8c7a1156 to your computer and use it in GitHub Desktop.
A benchmark for different Messenger classes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using Calcium.Messaging;
using Microsoft.Toolkit.Mvvm.Messaging;
using MvvmLightMessenger = GalaSoft.MvvmLight.Messaging.Messenger;
using CalciumMessenger = Calcium.Messaging.Messenger;
using MicrosoftToolkitMessenger = Microsoft.Toolkit.Mvvm.Messaging.Messenger;
namespace IocBenchmark.Benchmarks
{
[MemoryDiagnoser]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
[CategoriesColumn]
public class MessengerBenchmark
{
private const string DefaultChannel = nameof(DefaultChannel);
private const string MultipleChannels = nameof(MultipleChannels);
public const int NumberOfRecipients = 200;
public const int NumberOfIterations = 1000;
public const int RandomizeSteps = 1000;
private readonly A a = new A();
private readonly B b = new B();
private readonly C c = new C();
private readonly D d = new D();
private Recipient[] recipients;
private readonly MvvmLightMessenger mvvmLightMessenger = new MvvmLightMessenger();
private readonly CalciumMessenger calciumMessenger = new CalciumMessenger();
private readonly MicrosoftToolkitMessenger wctMessenger = new MicrosoftToolkitMessenger();
[GlobalSetup]
public void Setup()
{
this.recipients = Enumerable.Range(0, NumberOfRecipients).Select(_ => new Recipient()).ToArray();
foreach (var recipient in this.recipients)
{
Register(recipient);
}
var pending = new Queue<Recipient>();
var random = new Random(42);
for (int i = 0; i < RandomizeSteps; i++)
{
if (random.Next(0, 2) == 1)
{
ref Recipient recipient = ref this.recipients[random.Next(0, NumberOfRecipients)];
if (recipient is null) continue;
Unregister(recipient);
pending.Enqueue(recipient);
recipient = null;
}
else if (pending.TryDequeue(out Recipient recipient))
{
foreach (ref Recipient slot in this.recipients.AsSpan())
{
if (slot is null)
{
slot = recipient;
Register(recipient);
break;
}
}
}
}
int j = 0;
while (pending.TryDequeue(out Recipient recipient))
{
while (this.recipients[j] is null) j++;
this.recipients[j] = recipient;
Register(recipient);
}
}
private void Register(Recipient recipient)
{
this.mvvmLightMessenger.Register<A>(recipient, recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<B>(recipient, recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<C>(recipient, recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<D>(recipient, recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<A>(recipient, nameof(A), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<A>(recipient, nameof(B), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<A>(recipient, nameof(C), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<A>(recipient, nameof(D), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<B>(recipient, nameof(A), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<B>(recipient, nameof(B), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<B>(recipient, nameof(C), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<B>(recipient, nameof(D), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<C>(recipient, nameof(A), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<C>(recipient, nameof(B), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<C>(recipient, nameof(C), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<C>(recipient, nameof(D), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<D>(recipient, nameof(A), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<D>(recipient, nameof(B), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<D>(recipient, nameof(C), recipient.ReceiveMessage);
this.mvvmLightMessenger.Register<D>(recipient, nameof(D), recipient.ReceiveMessage);
this.calciumMessenger.Subscribe(recipient);
this.wctMessenger.Register<A>(recipient, recipient.ReceiveMessage);
this.wctMessenger.Register<B>(recipient, recipient.ReceiveMessage);
this.wctMessenger.Register<C>(recipient, recipient.ReceiveMessage);
this.wctMessenger.Register<D>(recipient, recipient.ReceiveMessage);
this.wctMessenger.Register<A, string>(recipient, nameof(A), recipient.ReceiveMessage);
this.wctMessenger.Register<A, string>(recipient, nameof(B), recipient.ReceiveMessage);
this.wctMessenger.Register<A, string>(recipient, nameof(C), recipient.ReceiveMessage);
this.wctMessenger.Register<A, string>(recipient, nameof(D), recipient.ReceiveMessage);
this.wctMessenger.Register<B, string>(recipient, nameof(A), recipient.ReceiveMessage);
this.wctMessenger.Register<B, string>(recipient, nameof(B), recipient.ReceiveMessage);
this.wctMessenger.Register<B, string>(recipient, nameof(C), recipient.ReceiveMessage);
this.wctMessenger.Register<B, string>(recipient, nameof(D), recipient.ReceiveMessage);
this.wctMessenger.Register<C, string>(recipient, nameof(A), recipient.ReceiveMessage);
this.wctMessenger.Register<C, string>(recipient, nameof(B), recipient.ReceiveMessage);
this.wctMessenger.Register<C, string>(recipient, nameof(C), recipient.ReceiveMessage);
this.wctMessenger.Register<C, string>(recipient, nameof(D), recipient.ReceiveMessage);
this.wctMessenger.Register<D, string>(recipient, nameof(A), recipient.ReceiveMessage);
this.wctMessenger.Register<D, string>(recipient, nameof(B), recipient.ReceiveMessage);
this.wctMessenger.Register<D, string>(recipient, nameof(C), recipient.ReceiveMessage);
this.wctMessenger.Register<D, string>(recipient, nameof(D), recipient.ReceiveMessage);
}
private void Unregister(Recipient recipient)
{
this.mvvmLightMessenger.Unregister(recipient);
this.calciumMessenger.Unsubscribe(recipient);
this.wctMessenger.Unregister(recipient);
}
[Benchmark(Baseline = true)]
[BenchmarkCategory(DefaultChannel)]
public void MVVM_DefaultChannel()
{
var a = this.a;
var b = this.b;
var c = this.c;
var d = this.d;
for (int i = NumberOfIterations; i > 0; i--)
{
this.mvvmLightMessenger.Send(a);
this.mvvmLightMessenger.Send(b);
this.mvvmLightMessenger.Send(c);
this.mvvmLightMessenger.Send(d);
}
}
[Benchmark]
[BenchmarkCategory(DefaultChannel)]
public async Task Calcium_DefaultChannel()
{
var a = this.a;
var b = this.b;
var c = this.c;
var d = this.d;
for (int i = NumberOfIterations; i > 0; i--)
{
await this.calciumMessenger.PublishAsync(a);
await this.calciumMessenger.PublishAsync(b);
await this.calciumMessenger.PublishAsync(c);
await this.calciumMessenger.PublishAsync(d);
}
}
[Benchmark]
[BenchmarkCategory(DefaultChannel)]
public void WCT_DefaultChannel()
{
var a = this.a;
var b = this.b;
var c = this.c;
var d = this.d;
for (int i = NumberOfIterations; i > 0; i--)
{
this.wctMessenger.Send(a);
this.wctMessenger.Send(b);
this.wctMessenger.Send(c);
this.wctMessenger.Send(d);
}
}
[Benchmark(Baseline = true)]
[BenchmarkCategory(MultipleChannels)]
public void MVVM_MultipleChannels()
{
var a = this.a;
var b = this.b;
var c = this.c;
var d = this.d;
for (int i = NumberOfIterations; i > 0; i--)
{
this.mvvmLightMessenger.Send(a, nameof(A));
this.mvvmLightMessenger.Send(a, nameof(B));
this.mvvmLightMessenger.Send(a, nameof(C));
this.mvvmLightMessenger.Send(a, nameof(D));
this.mvvmLightMessenger.Send(b, nameof(A));
this.mvvmLightMessenger.Send(b, nameof(B));
this.mvvmLightMessenger.Send(b, nameof(C));
this.mvvmLightMessenger.Send(b, nameof(D));
this.mvvmLightMessenger.Send(c, nameof(A));
this.mvvmLightMessenger.Send(c, nameof(B));
this.mvvmLightMessenger.Send(c, nameof(C));
this.mvvmLightMessenger.Send(c, nameof(D));
this.mvvmLightMessenger.Send(d, nameof(A));
this.mvvmLightMessenger.Send(d, nameof(B));
this.mvvmLightMessenger.Send(d, nameof(C));
this.mvvmLightMessenger.Send(d, nameof(D));
}
}
[Benchmark]
[BenchmarkCategory(MultipleChannels)]
public void WCT_MultipleChannels()
{
var a = this.a;
var b = this.b;
var c = this.c;
var d = this.d;
for (int i = NumberOfIterations; i > 0; i--)
{
this.wctMessenger.Send(a, nameof(A));
this.wctMessenger.Send(a, nameof(B));
this.wctMessenger.Send(a, nameof(C));
this.wctMessenger.Send(a, nameof(D));
this.wctMessenger.Send(b, nameof(A));
this.wctMessenger.Send(b, nameof(B));
this.wctMessenger.Send(b, nameof(C));
this.wctMessenger.Send(b, nameof(D));
this.wctMessenger.Send(c, nameof(A));
this.wctMessenger.Send(c, nameof(B));
this.wctMessenger.Send(c, nameof(C));
this.wctMessenger.Send(c, nameof(D));
this.wctMessenger.Send(d, nameof(A));
this.wctMessenger.Send(d, nameof(B));
this.wctMessenger.Send(d, nameof(C));
this.wctMessenger.Send(d, nameof(D));
}
}
}
public sealed class Recipient : IMessageSubscriber<A>, IMessageSubscriber<B>, IMessageSubscriber<C>, IMessageSubscriber<D>
{
[MethodImpl(MethodImplOptions.NoInlining)]
public void ReceiveMessage<T>(T message)
{
}
[MethodImpl(MethodImplOptions.NoInlining)]
public Task ReceiveMessageAsync(A message)
{
return Task.CompletedTask;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public Task ReceiveMessageAsync(B message)
{
return Task.CompletedTask;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public Task ReceiveMessageAsync(C message)
{
return Task.CompletedTask;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public Task ReceiveMessageAsync(D message)
{
return Task.CompletedTask;
}
}
public class A { }
public class B { }
public class C { }
public class D { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment