GFramework/GFramework.Cqrs.Benchmarks/Messaging/NotificationFanOutBenchmarks.cs
gewuyou b0102b5206 test(cqrs): 补充 notification publisher fan-out 基准对照
- 新增默认顺序发布器与 TaskWhenAllNotificationPublisher 的 fixed 4 handler fan-out benchmark 对照

- 更新 benchmark README 与 cqrs-rewrite 恢复文档,记录 RP-114 的性能结论与下一步
2026-05-08 17:42:48 +08:00

351 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2025-2026 GeWuYou
// SPDX-License-Identifier: Apache-2.0
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Order;
using System;
using System.Threading;
using System.Threading.Tasks;
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Ioc;
using GFramework.Core.Logging;
using GFramework.Cqrs.Abstractions.Cqrs;
using GFramework.Cqrs.Notification;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using GeneratedMediator = Mediator.Mediator;
namespace GFramework.Cqrs.Benchmarks.Messaging;
/// <summary>
/// 对比固定 4 个处理器的 notification fan-out publish 在 baseline、GFramework.CQRS、NuGet `Mediator`
/// 与 MediatR 之间的开销。
/// </summary>
[Config(typeof(Config))]
public class NotificationFanOutBenchmarks
{
private MicrosoftDiContainer _container = null!;
private ICqrsRuntime _sequentialRuntime = null!;
private ICqrsRuntime _taskWhenAllRuntime = null!;
private ServiceProvider _mediatrServiceProvider = null!;
private ServiceProvider _mediatorServiceProvider = null!;
private IPublisher _mediatrPublisher = null!;
private GeneratedMediator _mediator = null!;
private BenchmarkNotification _notification = null!;
private BenchmarkNotificationHandler1 _baselineHandler1 = null!;
private BenchmarkNotificationHandler2 _baselineHandler2 = null!;
private BenchmarkNotificationHandler3 _baselineHandler3 = null!;
private BenchmarkNotificationHandler4 _baselineHandler4 = null!;
/// <summary>
/// 配置 notification fan-out benchmark 的公共输出格式。
/// </summary>
private sealed class Config : ManualConfig
{
public Config()
{
AddJob(Job.Default);
AddColumnProvider(DefaultColumnProviders.Instance);
AddColumn(new CustomColumn("Scenario", static (_, _) => "NotificationFanOut"));
AddDiagnoser(MemoryDiagnoser.Default);
WithOrderer(new DefaultOrderer(SummaryOrderPolicy.FastestToSlowest, MethodOrderPolicy.Declared));
}
}
/// <summary>
/// 构建固定 4 处理器 notification publish 所需的最小 runtime 宿主和对照对象。
/// </summary>
[GlobalSetup]
public void Setup()
{
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider
{
MinLevel = LogLevel.Fatal
};
Fixture.Setup("NotificationFanOut", handlerCount: 4, pipelineCount: 0);
_baselineHandler1 = new BenchmarkNotificationHandler1();
_baselineHandler2 = new BenchmarkNotificationHandler2();
_baselineHandler3 = new BenchmarkNotificationHandler3();
_baselineHandler4 = new BenchmarkNotificationHandler4();
_container = BenchmarkHostFactory.CreateFrozenGFrameworkContainer(container =>
{
container.RegisterSingleton<GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>, BenchmarkNotificationHandler1>();
container.RegisterSingleton<GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>, BenchmarkNotificationHandler2>();
container.RegisterSingleton<GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>, BenchmarkNotificationHandler3>();
container.RegisterSingleton<GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>, BenchmarkNotificationHandler4>();
});
_sequentialRuntime = GFramework.Cqrs.CqrsRuntimeFactory.CreateRuntime(
_container,
LoggerFactoryResolver.Provider.CreateLogger(nameof(NotificationFanOutBenchmarks)));
_taskWhenAllRuntime = GFramework.Cqrs.CqrsRuntimeFactory.CreateRuntime(
_container,
LoggerFactoryResolver.Provider.CreateLogger($"{nameof(NotificationFanOutBenchmarks)}.{nameof(TaskWhenAllNotificationPublisher)}"),
new TaskWhenAllNotificationPublisher());
_mediatrServiceProvider = BenchmarkHostFactory.CreateMediatRServiceProvider(
services =>
{
services.AddSingleton<MediatR.INotificationHandler<BenchmarkNotification>, BenchmarkNotificationHandler1>();
services.AddSingleton<MediatR.INotificationHandler<BenchmarkNotification>, BenchmarkNotificationHandler2>();
services.AddSingleton<MediatR.INotificationHandler<BenchmarkNotification>, BenchmarkNotificationHandler3>();
services.AddSingleton<MediatR.INotificationHandler<BenchmarkNotification>, BenchmarkNotificationHandler4>();
},
typeof(NotificationFanOutBenchmarks),
static candidateType =>
candidateType == typeof(BenchmarkNotificationHandler1) ||
candidateType == typeof(BenchmarkNotificationHandler2) ||
candidateType == typeof(BenchmarkNotificationHandler3) ||
candidateType == typeof(BenchmarkNotificationHandler4),
ServiceLifetime.Singleton);
_mediatrPublisher = _mediatrServiceProvider.GetRequiredService<IPublisher>();
_mediatorServiceProvider = BenchmarkHostFactory.CreateMediatorServiceProvider(configure: null);
_mediator = _mediatorServiceProvider.GetRequiredService<GeneratedMediator>();
_notification = new BenchmarkNotification(Guid.NewGuid());
}
/// <summary>
/// 释放 MediatR 与 `Mediator` 对照组使用的 DI 宿主。
/// </summary>
[GlobalCleanup]
public void Cleanup()
{
BenchmarkCleanupHelper.DisposeAll(_container, _mediatrServiceProvider, _mediatorServiceProvider);
}
/// <summary>
/// 直接依次调用 4 个处理器,作为 fan-out dispatch 额外开销的 baseline。
/// </summary>
[Benchmark(Baseline = true)]
public async ValueTask PublishNotification_Baseline()
{
await _baselineHandler1.Handle(_notification, CancellationToken.None).ConfigureAwait(false);
await _baselineHandler2.Handle(_notification, CancellationToken.None).ConfigureAwait(false);
await _baselineHandler3.Handle(_notification, CancellationToken.None).ConfigureAwait(false);
await _baselineHandler4.Handle(_notification, CancellationToken.None).ConfigureAwait(false);
}
/// <summary>
/// 通过默认顺序发布器的 GFramework.CQRS runtime 发布固定 4 处理器的 notification。
/// </summary>
[Benchmark]
public ValueTask PublishNotification_GFrameworkCqrsSequential()
{
return _sequentialRuntime.PublishAsync(BenchmarkContext.Instance, _notification, CancellationToken.None);
}
/// <summary>
/// 通过内置 <c>Task.WhenAll(...)</c> 发布器的 GFramework.CQRS runtime 发布固定 4 处理器的 notification。
/// </summary>
[Benchmark]
public ValueTask PublishNotification_GFrameworkCqrsTaskWhenAll()
{
return _taskWhenAllRuntime.PublishAsync(BenchmarkContext.Instance, _notification, CancellationToken.None);
}
/// <summary>
/// 通过 MediatR 发布固定 4 处理器的 notification作为外部设计对照。
/// </summary>
[Benchmark]
public Task PublishNotification_MediatR()
{
return _mediatrPublisher.Publish(_notification, CancellationToken.None);
}
/// <summary>
/// 通过 `Mediator` source-generated concrete mediator 发布固定 4 处理器的 notification作为高性能对照组。
/// </summary>
[Benchmark]
public ValueTask PublishNotification_Mediator()
{
return _mediator.Publish(_notification, CancellationToken.None);
}
/// <summary>
/// Benchmark notification。
/// </summary>
/// <param name="Id">通知标识。</param>
public sealed record BenchmarkNotification(Guid Id) :
GFramework.Cqrs.Abstractions.Cqrs.INotification,
Mediator.INotification,
MediatR.INotification;
/// <summary>
/// 为 fan-out benchmark 提供统一的 no-op 处理逻辑。
/// </summary>
public abstract class BenchmarkNotificationHandlerBase
{
/// <summary>
/// 执行 benchmark 使用的最小处理逻辑。
/// </summary>
/// <param name="notification">当前 notification。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>已完成的值任务。</returns>
protected static ValueTask HandleCore(BenchmarkNotification notification, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(notification);
cancellationToken.ThrowIfCancellationRequested();
return ValueTask.CompletedTask;
}
}
/// <summary>
/// fan-out benchmark 的第 1 个 notification handler。
/// </summary>
public sealed class BenchmarkNotificationHandler1 :
BenchmarkNotificationHandlerBase,
GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>,
Mediator.INotificationHandler<BenchmarkNotification>,
MediatR.INotificationHandler<BenchmarkNotification>
{
/// <summary>
/// 处理 GFramework.CQRS notification。
/// </summary>
public ValueTask Handle(BenchmarkNotification notification, CancellationToken cancellationToken)
{
return HandleCore(notification, cancellationToken);
}
/// <summary>
/// 处理 NuGet `Mediator` notification。
/// </summary>
ValueTask Mediator.INotificationHandler<BenchmarkNotification>.Handle(
BenchmarkNotification notification,
CancellationToken cancellationToken)
{
return HandleCore(notification, cancellationToken);
}
/// <summary>
/// 处理 MediatR notification。
/// </summary>
Task MediatR.INotificationHandler<BenchmarkNotification>.Handle(
BenchmarkNotification notification,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
/// <summary>
/// fan-out benchmark 的第 2 个 notification handler。
/// </summary>
public sealed class BenchmarkNotificationHandler2 :
BenchmarkNotificationHandlerBase,
GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>,
Mediator.INotificationHandler<BenchmarkNotification>,
MediatR.INotificationHandler<BenchmarkNotification>
{
/// <summary>
/// 处理 GFramework.CQRS notification。
/// </summary>
public ValueTask Handle(BenchmarkNotification notification, CancellationToken cancellationToken)
{
return HandleCore(notification, cancellationToken);
}
/// <summary>
/// 处理 NuGet `Mediator` notification。
/// </summary>
ValueTask Mediator.INotificationHandler<BenchmarkNotification>.Handle(
BenchmarkNotification notification,
CancellationToken cancellationToken)
{
return HandleCore(notification, cancellationToken);
}
/// <summary>
/// 处理 MediatR notification。
/// </summary>
Task MediatR.INotificationHandler<BenchmarkNotification>.Handle(
BenchmarkNotification notification,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
/// <summary>
/// fan-out benchmark 的第 3 个 notification handler。
/// </summary>
public sealed class BenchmarkNotificationHandler3 :
BenchmarkNotificationHandlerBase,
GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>,
Mediator.INotificationHandler<BenchmarkNotification>,
MediatR.INotificationHandler<BenchmarkNotification>
{
/// <summary>
/// 处理 GFramework.CQRS notification。
/// </summary>
public ValueTask Handle(BenchmarkNotification notification, CancellationToken cancellationToken)
{
return HandleCore(notification, cancellationToken);
}
/// <summary>
/// 处理 NuGet `Mediator` notification。
/// </summary>
ValueTask Mediator.INotificationHandler<BenchmarkNotification>.Handle(
BenchmarkNotification notification,
CancellationToken cancellationToken)
{
return HandleCore(notification, cancellationToken);
}
/// <summary>
/// 处理 MediatR notification。
/// </summary>
Task MediatR.INotificationHandler<BenchmarkNotification>.Handle(
BenchmarkNotification notification,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
/// <summary>
/// fan-out benchmark 的第 4 个 notification handler。
/// </summary>
public sealed class BenchmarkNotificationHandler4 :
BenchmarkNotificationHandlerBase,
GFramework.Cqrs.Abstractions.Cqrs.INotificationHandler<BenchmarkNotification>,
Mediator.INotificationHandler<BenchmarkNotification>,
MediatR.INotificationHandler<BenchmarkNotification>
{
/// <summary>
/// 处理 GFramework.CQRS notification。
/// </summary>
public ValueTask Handle(BenchmarkNotification notification, CancellationToken cancellationToken)
{
return HandleCore(notification, cancellationToken);
}
/// <summary>
/// 处理 NuGet `Mediator` notification。
/// </summary>
ValueTask Mediator.INotificationHandler<BenchmarkNotification>.Handle(
BenchmarkNotification notification,
CancellationToken cancellationToken)
{
return HandleCore(notification, cancellationToken);
}
/// <summary>
/// 处理 MediatR notification。
/// </summary>
Task MediatR.INotificationHandler<BenchmarkNotification>.Handle(
BenchmarkNotification notification,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}