GFramework/GFramework.Cqrs.Benchmarks/Messaging/RequestInvokerBenchmarks.cs
gewuyou 3233151207 fix(ioc): 修复容器释放竞态与清理路径
- 修复 MicrosoftDiContainer 在等待线程与并发 Dispose 场景下泄露底层锁异常的问题
- 更新 IIocContainer 释放契约文档并移除 Clear 中不可达的 provider 释放逻辑
- 新增 benchmark cleanup helper、并发释放回归测试与 ai-plan 恢复入口
2026-05-06 20:23:16 +08:00

241 lines
9.0 KiB
C#
Raw Permalink 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.Collections.Generic;
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 MediatR;
using Microsoft.Extensions.DependencyInjection;
[assembly: GFramework.Cqrs.CqrsHandlerRegistryAttribute(
typeof(GFramework.Cqrs.Benchmarks.Messaging.GeneratedRequestInvokerBenchmarkRegistry))]
namespace GFramework.Cqrs.Benchmarks.Messaging;
/// <summary>
/// 对比 request steady-state dispatch 在 direct handler、GFramework 反射路径、GFramework generated invoker 路径与 MediatR 之间的开销差异。
/// </summary>
[Config(typeof(Config))]
public class RequestInvokerBenchmarks
{
private MicrosoftDiContainer _reflectionContainer = null!;
private ICqrsRuntime _reflectionRuntime = null!;
private MicrosoftDiContainer _generatedContainer = null!;
private ICqrsRuntime _generatedRuntime = null!;
private ServiceProvider _serviceProvider = null!;
private IMediator _mediatr = null!;
private ReflectionBenchmarkRequestHandler _baselineHandler = null!;
private ReflectionBenchmarkRequest _reflectionRequest = null!;
private GeneratedBenchmarkRequest _generatedRequest = null!;
private MediatRBenchmarkRequest _mediatrRequest = null!;
/// <summary>
/// 配置 request invoker benchmark 的公共输出格式。
/// </summary>
private sealed class Config : ManualConfig
{
public Config()
{
AddJob(Job.Default);
AddColumnProvider(DefaultColumnProviders.Instance);
AddColumn(new CustomColumn("Scenario", static (_, _) => "RequestInvoker"));
AddDiagnoser(MemoryDiagnoser.Default);
WithOrderer(new DefaultOrderer(SummaryOrderPolicy.FastestToSlowest, MethodOrderPolicy.Declared));
}
}
/// <summary>
/// 构建 reflection / generated / MediatR 三组 request dispatch 对照宿主。
/// </summary>
[GlobalSetup]
public void Setup()
{
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider
{
MinLevel = LogLevel.Fatal
};
Fixture.Setup("RequestInvoker", handlerCount: 1, pipelineCount: 0);
BenchmarkDispatcherCacheHelper.ClearDispatcherCaches();
_baselineHandler = new ReflectionBenchmarkRequestHandler();
_reflectionRequest = new ReflectionBenchmarkRequest(Guid.NewGuid());
_generatedRequest = new GeneratedBenchmarkRequest(Guid.NewGuid());
_mediatrRequest = new MediatRBenchmarkRequest(Guid.NewGuid());
_reflectionContainer = BenchmarkHostFactory.CreateFrozenGFrameworkContainer(static container =>
{
container.RegisterTransient<GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<ReflectionBenchmarkRequest, ReflectionBenchmarkResponse>, ReflectionBenchmarkRequestHandler>();
});
_reflectionRuntime = GFramework.Cqrs.CqrsRuntimeFactory.CreateRuntime(
_reflectionContainer,
LoggerFactoryResolver.Provider.CreateLogger(nameof(RequestInvokerBenchmarks) + ".Reflection"));
_generatedContainer = BenchmarkHostFactory.CreateFrozenGFrameworkContainer(container =>
{
container.RegisterCqrsHandlersFromAssembly(typeof(RequestInvokerBenchmarks).Assembly);
});
_generatedRuntime = GFramework.Cqrs.CqrsRuntimeFactory.CreateRuntime(
_generatedContainer,
LoggerFactoryResolver.Provider.CreateLogger(nameof(RequestInvokerBenchmarks) + ".Generated"));
_serviceProvider = BenchmarkHostFactory.CreateMediatRServiceProvider(
configure: null,
typeof(RequestInvokerBenchmarks),
static candidateType => candidateType == typeof(MediatRBenchmarkRequestHandler),
ServiceLifetime.Transient);
_mediatr = _serviceProvider.GetRequiredService<IMediator>();
}
/// <summary>
/// 释放 MediatR 对照组使用的 DI 宿主,并清理静态 dispatcher 缓存。
/// </summary>
[GlobalCleanup]
public void Cleanup()
{
try
{
BenchmarkCleanupHelper.DisposeAll(_reflectionContainer, _generatedContainer, _serviceProvider);
}
finally
{
BenchmarkDispatcherCacheHelper.ClearDispatcherCaches();
}
}
/// <summary>
/// 直接调用最小 request handler作为 dispatch 额外开销 baseline。
/// </summary>
[Benchmark(Baseline = true)]
public ValueTask<ReflectionBenchmarkResponse> SendRequest_Baseline()
{
return _baselineHandler.Handle(_reflectionRequest, CancellationToken.None);
}
/// <summary>
/// 通过 GFramework.CQRS 反射 request binding 路径发送 request。
/// </summary>
[Benchmark]
public ValueTask<ReflectionBenchmarkResponse> SendRequest_GFrameworkReflection()
{
return _reflectionRuntime.SendAsync(BenchmarkContext.Instance, _reflectionRequest, CancellationToken.None);
}
/// <summary>
/// 通过 generated request invoker provider 预热后的 GFramework.CQRS runtime 发送 request。
/// </summary>
[Benchmark]
public ValueTask<GeneratedBenchmarkResponse> SendRequest_GFrameworkGenerated()
{
return _generatedRuntime.SendAsync(BenchmarkContext.Instance, _generatedRequest, CancellationToken.None);
}
/// <summary>
/// 通过 MediatR 发送 request作为外部对照。
/// </summary>
[Benchmark]
public Task<MediatRBenchmarkResponse> SendRequest_MediatR()
{
return _mediatr.Send(_mediatrRequest, CancellationToken.None);
}
/// <summary>
/// Reflection runtime request。
/// </summary>
/// <param name="Id">请求标识。</param>
public sealed record ReflectionBenchmarkRequest(Guid Id) :
GFramework.Cqrs.Abstractions.Cqrs.IRequest<ReflectionBenchmarkResponse>;
/// <summary>
/// Reflection runtime response。
/// </summary>
/// <param name="Id">响应标识。</param>
public sealed record ReflectionBenchmarkResponse(Guid Id);
/// <summary>
/// Generated runtime request。
/// </summary>
/// <param name="Id">请求标识。</param>
public sealed record GeneratedBenchmarkRequest(Guid Id) :
GFramework.Cqrs.Abstractions.Cqrs.IRequest<GeneratedBenchmarkResponse>;
/// <summary>
/// Generated runtime response。
/// </summary>
/// <param name="Id">响应标识。</param>
public sealed record GeneratedBenchmarkResponse(Guid Id);
/// <summary>
/// MediatR request。
/// </summary>
/// <param name="Id">请求标识。</param>
public sealed record MediatRBenchmarkRequest(Guid Id) : MediatR.IRequest<MediatRBenchmarkResponse>;
/// <summary>
/// MediatR response。
/// </summary>
/// <param name="Id">响应标识。</param>
public sealed record MediatRBenchmarkResponse(Guid Id);
/// <summary>
/// Reflection runtime 的最小 request handler。
/// </summary>
public sealed class ReflectionBenchmarkRequestHandler :
GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<ReflectionBenchmarkRequest, ReflectionBenchmarkResponse>
{
/// <summary>
/// 处理 reflection benchmark request。
/// </summary>
public ValueTask<ReflectionBenchmarkResponse> Handle(
ReflectionBenchmarkRequest request,
CancellationToken cancellationToken)
{
return ValueTask.FromResult(new ReflectionBenchmarkResponse(request.Id));
}
}
/// <summary>
/// Generated runtime 的最小 request handler。
/// </summary>
public sealed class GeneratedBenchmarkRequestHandler :
GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<GeneratedBenchmarkRequest, GeneratedBenchmarkResponse>
{
/// <summary>
/// 处理 generated benchmark request。
/// </summary>
public ValueTask<GeneratedBenchmarkResponse> Handle(
GeneratedBenchmarkRequest request,
CancellationToken cancellationToken)
{
return ValueTask.FromResult(new GeneratedBenchmarkResponse(request.Id));
}
}
/// <summary>
/// MediatR 对照组的最小 request handler。
/// </summary>
public sealed class MediatRBenchmarkRequestHandler :
MediatR.IRequestHandler<MediatRBenchmarkRequest, MediatRBenchmarkResponse>
{
/// <summary>
/// 处理 MediatR benchmark request。
/// </summary>
public Task<MediatRBenchmarkResponse> Handle(
MediatRBenchmarkRequest request,
CancellationToken cancellationToken)
{
return Task.FromResult(new MediatRBenchmarkResponse(request.Id));
}
}
}