Skip to content
9 changes: 5 additions & 4 deletions GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,16 @@ internal static IAsyncEnumerable<TResponse> CreateScopedMediatRStream<TResponse>
/// <param name="configure">补充当前场景的显式服务注册。</param>
/// <returns>可直接解析 generated `Mediator.Mediator` 的 DI 宿主。</returns>
/// <remarks>
/// 当前 benchmark 只把 `Mediator` 作为单例 steady-state 对照组接入,
/// 因为它的 lifetime 由 source generator 在编译期塑形;若后续需要 `Transient` / `Scoped` 矩阵,
/// 应按 `Mediator` 官方 benchmark 的做法拆成独立 build config,而不是在同一编译产物里混用多个 lifetime。
/// `Mediator` 的 DI lifetime 由 source generator 在编译期固定到整个位于当前项目中的生成产物上。
/// 因此 benchmark 工程必须统一使用一套 compile-time 常量配置;这里显式收敛为 `Singleton`,
/// 避免同一编译产物里混入多个 `AddMediator` lifetime 形状后,在 BenchmarkDotNet 自动生成宿主中触发
/// “generated code lifetime 与 runtime options 不一致”的启动失败。
/// </remarks>
internal static ServiceProvider CreateMediatorServiceProvider(Action<IServiceCollection>? configure)
{
var services = new ServiceCollection();
configure?.Invoke(services);
services.AddMediator();
services.AddMediator(static options => options.ServiceLifetime = ServiceLifetime.Singleton);
return services.BuildServiceProvider();
}

Expand Down
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
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ namespace GFramework.Cqrs.Benchmarks.Messaging;
/// 当前矩阵覆盖 `Singleton`、`Scoped` 与 `Transient`。
/// 其中 `Scoped` 会在每次 request 分发时显式创建并释放真实的 DI 作用域,
/// 避免把 scoped handler 错误地压到根容器解析而扭曲生命周期对照。
/// NuGet `Mediator` 的 DI lifetime 由 source generator 在编译期固定到整个 benchmark 项目,
/// 不能在同一份生成产物里同时切换 `Singleton`、`Scoped` 与 `Transient`。
/// 因此该矩阵当前只比较 `GFramework.Cqrs` 与 `MediatR` 的生命周期开销;`Mediator` 仍保留在其他
/// steady-state / startup benchmark 中作为单一 compile-time 形状对照。
/// </remarks>
[Config(typeof(Config))]
public class RequestLifetimeBenchmarks
Expand Down Expand Up @@ -151,6 +155,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 +165,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 +185,7 @@ public ValueTask<BenchmarkResponse> SendRequest_GFrameworkCqrs()
/// <summary>
/// 通过 MediatR 发送 request,作为外部对照。
/// </summary>
/// <returns>代表当前 MediatR request dispatch 完成的任务。</returns>
[Benchmark]
public Task<BenchmarkResponse> SendRequest_MediatR()
{
Expand All @@ -194,7 +201,7 @@ public Task<BenchmarkResponse> SendRequest_MediatR()
}

/// <summary>
/// 按生命周期把 benchmark request handler 注册到 GFramework 容器。
/// 按生命周期把 benchmark request handler 注册到 GFramework 容器。
/// </summary>
/// <param name="container">当前 benchmark 拥有并负责释放的容器。</param>
/// <param name="lifetime">待比较的 handler 生命周期。</param>
Expand Down Expand Up @@ -241,7 +248,7 @@ private static ServiceLifetime ResolveMediatRLifetime(HandlerLifetime lifetime)
}

/// <summary>
/// Benchmark request。
/// Benchmark request。
/// </summary>
/// <param name="Id">请求标识。</param>
public sealed record BenchmarkRequest(Guid Id) :
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
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public void Cleanup()
/// <summary>
/// 返回已构建宿主中的 MediatR mediator,作为 initialization 组的句柄解析 baseline。
/// </summary>
/// <returns>当前 benchmark 复用的 MediatR mediator。</returns>
[Benchmark(Baseline = true)]
[BenchmarkCategory("Initialization")]
public IMediator Initialization_MediatR()
Expand All @@ -107,6 +108,7 @@ public IMediator Initialization_MediatR()
/// <summary>
/// 返回已构建宿主中的 GFramework.CQRS runtime,确保与 MediatR baseline 处于相同初始化阶段。
/// </summary>
/// <returns>当前 benchmark 复用的 GFramework.CQRS runtime。</returns>
[Benchmark]
[BenchmarkCategory("Initialization")]
public ICqrsRuntime Initialization_GFrameworkCqrs()
Expand All @@ -117,6 +119,7 @@ public ICqrsRuntime Initialization_GFrameworkCqrs()
/// <summary>
/// 返回已构建宿主中的 `Mediator` concrete mediator,作为 source-generated 对照组的初始化句柄。
/// </summary>
/// <returns>当前 benchmark 复用的 `Mediator` concrete mediator。</returns>
[Benchmark]
[BenchmarkCategory("Initialization")]
public GeneratedMediator Initialization_Mediator()
Expand All @@ -127,6 +130,7 @@ public GeneratedMediator Initialization_Mediator()
/// <summary>
/// 在新宿主上首次发送 request,作为 MediatR 的 cold-start baseline。
/// </summary>
/// <returns>当前 request 的响应结果。</returns>
[Benchmark(Baseline = true)]
[BenchmarkCategory("ColdStart")]
public async Task<BenchmarkResponse> ColdStart_MediatR()
Expand All @@ -139,6 +143,7 @@ public async Task<BenchmarkResponse> ColdStart_MediatR()
/// <summary>
/// 在新 runtime 上首次发送 request,量化 GFramework.CQRS 的 first-hit 成本。
/// </summary>
/// <returns>当前 request 的响应结果。</returns>
[Benchmark]
[BenchmarkCategory("ColdStart")]
public async ValueTask<BenchmarkResponse> ColdStart_GFrameworkCqrs()
Expand All @@ -151,6 +156,7 @@ public async ValueTask<BenchmarkResponse> ColdStart_GFrameworkCqrs()
/// <summary>
/// 在新的 `Mediator` 宿主上首次发送 request,量化 source-generated concrete path 的 cold-start 成本。
/// </summary>
/// <returns>当前 request 的响应结果。</returns>
[Benchmark]
[BenchmarkCategory("ColdStart")]
public async ValueTask<BenchmarkResponse> ColdStart_Mediator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public void Cleanup()
/// <summary>
/// 直接调用最小 stream handler,并按当前观测模式消费 stream,作为 dispatch 额外开销 baseline。
/// </summary>
/// <returns>代表基线 stream 按当前观测模式消费完成的值任务。</returns>
[Benchmark(Baseline = true)]
public ValueTask Stream_Baseline()
{
Expand All @@ -152,6 +153,7 @@ public ValueTask Stream_Baseline()
/// <summary>
/// 通过 GFramework.CQRS 反射 stream binding 路径创建 stream,并按当前观测模式消费。
/// </summary>
/// <returns>代表当前 GFramework.CQRS 反射 stream 按观测模式消费完成的值任务。</returns>
[Benchmark]
public ValueTask Stream_GFrameworkReflection()
{
Expand All @@ -166,6 +168,7 @@ public ValueTask Stream_GFrameworkReflection()
/// <summary>
/// 通过 generated stream invoker provider 预热后的 GFramework.CQRS runtime 创建 stream,并按当前观测模式消费。
/// </summary>
/// <returns>代表当前 GFramework.CQRS generated stream 按观测模式消费完成的值任务。</returns>
[Benchmark]
public ValueTask Stream_GFrameworkGenerated()
{
Expand All @@ -180,6 +183,7 @@ public ValueTask Stream_GFrameworkGenerated()
/// <summary>
/// 通过 MediatR 创建 stream,并按当前观测模式消费,作为外部对照。
/// </summary>
/// <returns>代表当前 MediatR stream 按观测模式消费完成的值任务。</returns>
[Benchmark]
public ValueTask Stream_MediatR()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ public void Cleanup()
/// <summary>
/// 直接调用 handler,并按当前观测模式消费 stream,作为不同生命周期矩阵下的 dispatch 额外开销 baseline。
/// </summary>
/// <returns>代表基线 handler stream 按当前观测模式消费完成的值任务。</returns>
[Benchmark(Baseline = true)]
public ValueTask Stream_Baseline()
{
Expand All @@ -157,6 +158,7 @@ public ValueTask Stream_Baseline()
/// <summary>
/// 通过 GFramework.CQRS reflection stream binding 路径创建 stream,并按当前观测模式消费。
/// </summary>
/// <returns>代表当前 reflection stream 按当前观测模式消费完成的值任务。</returns>
[Benchmark]
public ValueTask Stream_GFrameworkReflection()
{
Expand All @@ -183,6 +185,7 @@ public ValueTask Stream_GFrameworkReflection()
/// <summary>
/// 通过 generated stream invoker provider 预热后的 GFramework.CQRS runtime 创建 stream,并按当前观测模式消费。
/// </summary>
/// <returns>代表当前 generated stream 按当前观测模式消费完成的值任务。</returns>
[Benchmark]
public ValueTask Stream_GFrameworkGenerated()
{
Expand All @@ -209,6 +212,7 @@ public ValueTask Stream_GFrameworkGenerated()
/// <summary>
/// 通过 MediatR 创建 stream,并按当前观测模式消费,作为外部对照。
/// </summary>
/// <returns>代表当前 MediatR stream 按当前观测模式消费完成的值任务。</returns>
[Benchmark]
public ValueTask Stream_MediatR()
{
Expand Down
Loading
Loading