Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
namespace GFramework.Cqrs.Benchmarks.Messaging;

/// <summary>
/// 对比单处理器 notification 在 GFramework.CQRS 与 MediatR 之间的 publish 开销。
/// 对比单处理器 notification 在 GFramework.CQRS、NuGet `Mediator` 与 MediatR 之间的 publish 开销。
/// </summary>
[Config(typeof(Config))]
public class NotificationBenchmarks
Expand Down Expand Up @@ -95,6 +95,7 @@ public void Cleanup()
/// <summary>
/// 通过 GFramework.CQRS runtime 发布 notification。
/// </summary>
/// <returns>代表当前 GFramework.CQRS publish 完成的值任务。</returns>
[Benchmark(Baseline = true)]
public ValueTask PublishNotification_GFrameworkCqrs()
{
Expand All @@ -104,6 +105,7 @@ public ValueTask PublishNotification_GFrameworkCqrs()
/// <summary>
/// 通过 MediatR 发布 notification,作为外部设计对照。
/// </summary>
/// <returns>代表当前 MediatR publish 完成的任务。</returns>
[Benchmark]
public Task PublishNotification_MediatR()
{
Expand All @@ -113,6 +115,7 @@ public Task PublishNotification_MediatR()
/// <summary>
/// 通过 `Mediator` source-generated concrete mediator 发布 notification,作为高性能对照组。
/// </summary>
/// <returns>代表当前 `Mediator` publish 完成的值任务。</returns>
[Benchmark]
public ValueTask PublishNotification_Mediator()
{
Expand All @@ -129,7 +132,7 @@ public sealed record BenchmarkNotification(Guid Id) :
MediatR.INotification;

/// <summary>
/// 同时实现 GFramework.CQRS 与 MediatR 契约的最小 notification handler。
/// 同时实现 GFramework.CQRS、NuGet `Mediator` 与 MediatR 契约的最小 notification handler。
/// </summary>
public sealed class BenchmarkNotificationHandler :
GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public void Cleanup()
/// <summary>
/// 直接依次调用 4 个处理器,作为 fan-out dispatch 额外开销的 baseline。
/// </summary>
/// <returns>代表基线顺序调用 4 个处理器完成当前 notification 处理的值任务。</returns>
[Benchmark(Baseline = true)]
public async ValueTask PublishNotification_Baseline()
{
Expand All @@ -135,6 +136,7 @@ public async ValueTask PublishNotification_Baseline()
/// <summary>
/// 通过默认顺序发布器的 GFramework.CQRS runtime 发布固定 4 处理器的 notification。
/// </summary>
/// <returns>代表当前默认顺序发布器 publish 完成的值任务。</returns>
[Benchmark]
public ValueTask PublishNotification_GFrameworkCqrsSequential()
{
Expand All @@ -144,6 +146,7 @@ public ValueTask PublishNotification_GFrameworkCqrsSequential()
/// <summary>
/// 通过内置 <c>Task.WhenAll(...)</c> 发布器的 GFramework.CQRS runtime 发布固定 4 处理器的 notification。
/// </summary>
/// <returns>代表当前 <c>Task.WhenAll(...)</c> 发布器 publish 完成的值任务。</returns>
[Benchmark]
public ValueTask PublishNotification_GFrameworkCqrsTaskWhenAll()
{
Expand All @@ -153,6 +156,7 @@ public ValueTask PublishNotification_GFrameworkCqrsTaskWhenAll()
/// <summary>
/// 通过 MediatR 发布固定 4 处理器的 notification,作为外部设计对照。
/// </summary>
/// <returns>代表当前 MediatR publish 完成的任务。</returns>
[Benchmark]
public Task PublishNotification_MediatR()
{
Expand All @@ -162,6 +166,7 @@ public Task PublishNotification_MediatR()
/// <summary>
/// 通过 `Mediator` source-generated concrete mediator 发布固定 4 处理器的 notification,作为高性能对照组。
/// </summary>
/// <returns>代表当前 `Mediator` publish 完成的值任务。</returns>
[Benchmark]
public ValueTask PublishNotification_Mediator()
{
Expand Down
6 changes: 5 additions & 1 deletion GFramework.Cqrs.Benchmarks/Messaging/RequestBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public void Cleanup()
/// <summary>
/// 直接调用 handler,作为 dispatch 额外开销的 baseline。
/// </summary>
/// <returns>代表基线 handler 完成当前 request 处理的值任务。</returns>
[Benchmark(Baseline = true)]
public ValueTask<BenchmarkResponse> SendRequest_Baseline()
{
Expand All @@ -113,6 +114,7 @@ public ValueTask<BenchmarkResponse> SendRequest_Baseline()
/// <summary>
/// 通过 GFramework.CQRS runtime 发送 request。
/// </summary>
/// <returns>代表当前 GFramework.CQRS request dispatch 完成的值任务。</returns>
[Benchmark]
public ValueTask<BenchmarkResponse> SendRequest_GFrameworkCqrs()
{
Expand All @@ -122,6 +124,7 @@ public ValueTask<BenchmarkResponse> SendRequest_GFrameworkCqrs()
/// <summary>
/// 通过 MediatR 发送 request,作为外部设计对照。
/// </summary>
/// <returns>代表当前 MediatR request dispatch 完成的任务。</returns>
[Benchmark]
public Task<BenchmarkResponse> SendRequest_MediatR()
{
Expand All @@ -131,6 +134,7 @@ public Task<BenchmarkResponse> SendRequest_MediatR()
/// <summary>
/// 通过 `ai-libs/Mediator` 的 source-generated concrete mediator 发送 request,作为高性能对照组。
/// </summary>
/// <returns>代表当前 `Mediator` request dispatch 完成的值任务。</returns>
[Benchmark]
public ValueTask<BenchmarkResponse> SendRequest_Mediator()
{
Expand All @@ -153,7 +157,7 @@ public sealed record BenchmarkRequest(Guid Id) :
public sealed record BenchmarkResponse(Guid Id);

/// <summary>
/// 同时实现 GFramework.CQRS 与 MediatR 契约的最小 request handler。
/// 同时实现 GFramework.CQRS、NuGet `Mediator` 与 MediatR 契约的最小 request handler。
/// </summary>
public sealed class BenchmarkRequestHandler :
GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<BenchmarkRequest, BenchmarkResponse>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ public void Cleanup()
/// <summary>
/// 直接调用最小 request handler,作为 dispatch 额外开销 baseline。
/// </summary>
/// <returns>代表基线 request handler 完成当前 request 处理的值任务。</returns>
[Benchmark(Baseline = true)]
public ValueTask<ReflectionBenchmarkResponse> SendRequest_Baseline()
{
Expand All @@ -125,6 +126,7 @@ public ValueTask<ReflectionBenchmarkResponse> SendRequest_Baseline()
/// <summary>
/// 通过 GFramework.CQRS 反射 request binding 路径发送 request。
/// </summary>
/// <returns>代表当前 reflection request dispatch 完成的值任务。</returns>
[Benchmark]
public ValueTask<ReflectionBenchmarkResponse> SendRequest_GFrameworkReflection()
{
Expand All @@ -134,6 +136,7 @@ public ValueTask<ReflectionBenchmarkResponse> SendRequest_GFrameworkReflection()
/// <summary>
/// 通过 generated request invoker provider 预热后的 GFramework.CQRS runtime 发送 request。
/// </summary>
/// <returns>代表当前 generated request dispatch 完成的值任务。</returns>
[Benchmark]
public ValueTask<GeneratedBenchmarkResponse> SendRequest_GFrameworkGenerated()
{
Expand All @@ -143,6 +146,7 @@ public ValueTask<GeneratedBenchmarkResponse> SendRequest_GFrameworkGenerated()
/// <summary>
/// 通过 MediatR 发送 request,作为外部对照。
/// </summary>
/// <returns>代表当前 MediatR request dispatch 完成的任务。</returns>
[Benchmark]
public Task<MediatRBenchmarkResponse> SendRequest_MediatR()
{
Expand Down
118 changes: 115 additions & 3 deletions GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using GFramework.Cqrs.Abstractions.Cqrs;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using GeneratedMediator = Mediator.Mediator;

namespace GFramework.Cqrs.Benchmarks.Messaging;

Expand All @@ -35,7 +36,9 @@ public class RequestLifetimeBenchmarks
private ScopedBenchmarkContainer? _scopedContainer;
private ICqrsRuntime? _scopedRuntime;
private ServiceProvider _serviceProvider = null!;
private ServiceProvider _mediatorServiceProvider = null!;
private IMediator? _mediatr;
private GeneratedMediator? _mediator;
private BenchmarkRequestHandler _baselineHandler = null!;
private BenchmarkRequest _request = null!;
private ILogger _runtimeLogger = null!;
Expand Down Expand Up @@ -83,7 +86,7 @@ public Config()
}

/// <summary>
/// 构建当前生命周期下的 GFramework 与 MediatR request 对照宿主。
/// 构建当前生命周期下的 GFramework、NuGet `Mediator` 与 MediatR request 对照宿主。
/// </summary>
[GlobalSetup]
public void Setup()
Expand Down Expand Up @@ -130,6 +133,12 @@ public void Setup()
{
_mediatr = _serviceProvider.GetRequiredService<IMediator>();
}

_mediatorServiceProvider = CreateMediatorServiceProvider(Lifetime);
if (Lifetime != HandlerLifetime.Scoped)
{
_mediator = _mediatorServiceProvider.GetRequiredService<GeneratedMediator>();
}
}

/// <summary>
Expand All @@ -140,7 +149,7 @@ public void Cleanup()
{
try
{
BenchmarkCleanupHelper.DisposeAll(_container, _serviceProvider);
BenchmarkCleanupHelper.DisposeAll(_container, _serviceProvider, _mediatorServiceProvider);
}
finally
{
Expand All @@ -151,6 +160,7 @@ public void Cleanup()
/// <summary>
/// 直接调用 handler,作为不同生命周期矩阵下的 dispatch 额外开销 baseline。
/// </summary>
/// <returns>代表基线 request handler 完成当前 request 处理的值任务。</returns>
[Benchmark(Baseline = true)]
public ValueTask<BenchmarkResponse> SendRequest_Baseline()
{
Expand All @@ -160,6 +170,7 @@ public ValueTask<BenchmarkResponse> SendRequest_Baseline()
/// <summary>
/// 通过 GFramework.CQRS runtime 发送 request。
/// </summary>
/// <returns>代表当前 GFramework.CQRS request dispatch 完成的值任务。</returns>
[Benchmark]
public ValueTask<BenchmarkResponse> SendRequest_GFrameworkCqrs()
{
Expand All @@ -179,6 +190,7 @@ public ValueTask<BenchmarkResponse> SendRequest_GFrameworkCqrs()
/// <summary>
/// 通过 MediatR 发送 request,作为外部对照。
/// </summary>
/// <returns>代表当前 MediatR request dispatch 完成的任务。</returns>
[Benchmark]
public Task<BenchmarkResponse> SendRequest_MediatR()
{
Expand All @@ -193,6 +205,24 @@ public Task<BenchmarkResponse> SendRequest_MediatR()
return _mediatr!.Send(_request, CancellationToken.None);
}

/// <summary>
/// 通过 `Mediator` source-generated concrete mediator 发送 request,作为 compile-time 对照。
/// </summary>
/// <returns>代表当前 `Mediator` request dispatch 完成的值任务。</returns>
[Benchmark]
public ValueTask<BenchmarkResponse> SendRequest_Mediator()
{
if (Lifetime == HandlerLifetime.Scoped)
{
return SendScopedMediatorRequestAsync(
_mediatorServiceProvider,
_request,
CancellationToken.None);
}

return _mediator!.Send(_request, CancellationToken.None);
}

/// <summary>
/// 按生命周期把 benchmark request handler 注册到 GFramework 容器。
/// </summary>
Expand Down Expand Up @@ -240,12 +270,83 @@ private static ServiceLifetime ResolveMediatRLifetime(HandlerLifetime lifetime)
};
}

/// <summary>
/// 构建只承载当前 benchmark request handler 的最小 `Mediator` 对照宿主,并按生命周期切换生成器注册形状。
/// </summary>
/// <param name="lifetime">待比较的 handler 生命周期。</param>
/// <returns>可直接解析 generated `Mediator.Mediator` 的 DI 宿主。</returns>
private static ServiceProvider CreateMediatorServiceProvider(HandlerLifetime lifetime)
{
return lifetime switch
{
HandlerLifetime.Singleton => CreateSingletonMediatorServiceProvider(),
HandlerLifetime.Scoped => CreateScopedMediatorServiceProvider(),
HandlerLifetime.Transient => CreateTransientMediatorServiceProvider(),
_ => throw new ArgumentOutOfRangeException(nameof(lifetime), lifetime, "Unsupported benchmark handler lifetime.")
};
}

/// <summary>
/// 在真实的 request 级作用域内执行一次 `Mediator` request 分发。
/// </summary>
/// <typeparam name="TResponse">请求响应类型。</typeparam>
/// <param name="rootServiceProvider">当前 benchmark 的根 <see cref="ServiceProvider" />。</param>
/// <param name="request">要发送的 request。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>当前 request 的响应结果。</returns>
private static async ValueTask<TResponse> SendScopedMediatorRequestAsync<TResponse>(
ServiceProvider rootServiceProvider,
Mediator.IRequest<TResponse> request,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(rootServiceProvider);
ArgumentNullException.ThrowIfNull(request);

using var scope = rootServiceProvider.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<GeneratedMediator>();
return await mediator.Send(request, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// 构建 singleton 生命周期的 `Mediator` 对照宿主。
/// </summary>
/// <returns>按 singleton 形状生成 DI 注册的 `Mediator` 宿主。</returns>
private static ServiceProvider CreateSingletonMediatorServiceProvider()
{
var services = new ServiceCollection();
services.AddMediator(static options => options.ServiceLifetime = ServiceLifetime.Singleton);
return services.BuildServiceProvider();
}

/// <summary>
/// 构建 scoped 生命周期的 `Mediator` 对照宿主。
/// </summary>
/// <returns>按 scoped 形状生成 DI 注册的 `Mediator` 宿主。</returns>
private static ServiceProvider CreateScopedMediatorServiceProvider()
{
var services = new ServiceCollection();
services.AddMediator(static options => options.ServiceLifetime = ServiceLifetime.Scoped);
return services.BuildServiceProvider();
}

/// <summary>
/// 构建 transient 生命周期的 `Mediator` 对照宿主。
/// </summary>
/// <returns>按 transient 形状生成 DI 注册的 `Mediator` 宿主。</returns>
private static ServiceProvider CreateTransientMediatorServiceProvider()
{
var services = new ServiceCollection();
services.AddMediator(static options => options.ServiceLifetime = ServiceLifetime.Transient);
return services.BuildServiceProvider();
}

/// <summary>
/// Benchmark request。
/// </summary>
/// <param name="Id">请求标识。</param>
public sealed record BenchmarkRequest(Guid Id) :
GFramework.Cqrs.Abstractions.Cqrs.IRequest<BenchmarkResponse>,
Mediator.IRequest<BenchmarkResponse>,
MediatR.IRequest<BenchmarkResponse>;

/// <summary>
Expand All @@ -255,10 +356,11 @@ public sealed record BenchmarkRequest(Guid Id) :
public sealed record BenchmarkResponse(Guid Id);

/// <summary>
/// 同时实现 GFramework.CQRS 与 MediatR 契约的最小 request handler。
/// 同时实现 GFramework.CQRS、NuGet `Mediator` 与 MediatR 契约的最小 request handler。
/// </summary>
public sealed class BenchmarkRequestHandler :
GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<BenchmarkRequest, BenchmarkResponse>,
Mediator.IRequestHandler<BenchmarkRequest, BenchmarkResponse>,
MediatR.IRequestHandler<BenchmarkRequest, BenchmarkResponse>
{
/// <summary>
Expand All @@ -269,6 +371,16 @@ public ValueTask<BenchmarkResponse> Handle(BenchmarkRequest request, Cancellatio
return ValueTask.FromResult(new BenchmarkResponse(request.Id));
}

/// <summary>
/// 处理 NuGet `Mediator` request。
/// </summary>
ValueTask<BenchmarkResponse> Mediator.IRequestHandler<BenchmarkRequest, BenchmarkResponse>.Handle(
BenchmarkRequest request,
CancellationToken cancellationToken)
{
return Handle(request, cancellationToken);
}

/// <summary>
/// 处理 MediatR request。
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public void Cleanup()
/// <summary>
/// 直接调用 handler,作为 pipeline 编排之外的基线。
/// </summary>
/// <returns>代表基线 handler 完成当前 request 处理的值任务。</returns>
[Benchmark(Baseline = true)]
public ValueTask<BenchmarkResponse> SendRequest_Baseline()
{
Expand All @@ -122,6 +123,7 @@ public ValueTask<BenchmarkResponse> SendRequest_Baseline()
/// <summary>
/// 通过 GFramework.CQRS runtime 发送 request,并按当前矩阵配置执行 pipeline。
/// </summary>
/// <returns>代表当前 GFramework.CQRS request pipeline dispatch 完成的值任务。</returns>
[Benchmark]
public ValueTask<BenchmarkResponse> SendRequest_GFrameworkCqrs()
{
Expand All @@ -131,6 +133,7 @@ public ValueTask<BenchmarkResponse> SendRequest_GFrameworkCqrs()
/// <summary>
/// 通过 MediatR 发送 request,并按当前矩阵配置执行 pipeline,作为外部设计对照。
/// </summary>
/// <returns>代表当前 MediatR request pipeline dispatch 完成的任务。</returns>
[Benchmark]
public Task<BenchmarkResponse> SendRequest_MediatR()
{
Expand Down
Loading
Loading