mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-10 02:59:02 +08:00
test(cqrs-benchmarks): 补充stream lifetime双观测口径
- 新增 StreamLifetimeBenchmarks 的 FirstItem 与 DrainAll 观测模式,用于拆分建流瞬时成本与完整枚举成本 - 更新 cqrs-rewrite 恢复文档与 benchmark README,同步 RP-127 的验证结果、branch diff 与下一恢复点
This commit is contained in:
parent
b7fa3eee29
commit
9ffe3ba237
@ -21,7 +21,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
namespace GFramework.Cqrs.Benchmarks.Messaging;
|
||||
|
||||
/// <summary>
|
||||
/// 对比 stream 完整枚举在不同 handler 生命周期下的额外开销。
|
||||
/// 对比 stream 在不同 handler 生命周期与观测方式下的额外开销。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 当前矩阵只覆盖 `Singleton` 与 `Transient`。
|
||||
@ -48,6 +48,12 @@ public class StreamLifetimeBenchmarks
|
||||
[Params(HandlerLifetime.Singleton, HandlerLifetime.Transient)]
|
||||
public HandlerLifetime Lifetime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 控制当前 benchmark 观察“只推进首个元素”还是“完整枚举整个 stream”。
|
||||
/// </summary>
|
||||
[Params(StreamObservation.FirstItem, StreamObservation.DrainAll)]
|
||||
public StreamObservation Observation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可公平比较的 benchmark handler 生命周期集合。
|
||||
/// </summary>
|
||||
@ -64,6 +70,22 @@ public class StreamLifetimeBenchmarks
|
||||
Transient
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于拆分 stream dispatch 与后续枚举成本的观测模式。
|
||||
/// </summary>
|
||||
public enum StreamObservation
|
||||
{
|
||||
/// <summary>
|
||||
/// 只推进到首个元素后立即释放枚举器。
|
||||
/// </summary>
|
||||
FirstItem,
|
||||
|
||||
/// <summary>
|
||||
/// 完整枚举整个 stream,保留原有 benchmark 语义。
|
||||
/// </summary>
|
||||
DrainAll
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置 stream 生命周期 benchmark 的公共输出格式。
|
||||
/// </summary>
|
||||
@ -141,59 +163,49 @@ public class StreamLifetimeBenchmarks
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接调用 handler 并完整枚举,作为不同生命周期矩阵下的 dispatch 额外开销 baseline。
|
||||
/// 直接调用 handler,并按当前观测模式消费 stream,作为不同生命周期矩阵下的 dispatch 额外开销 baseline。
|
||||
/// </summary>
|
||||
[Benchmark(Baseline = true)]
|
||||
public async ValueTask Stream_Baseline()
|
||||
public ValueTask Stream_Baseline()
|
||||
{
|
||||
await foreach (var response in _baselineHandler.Handle(_reflectionRequest, CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
_ = response;
|
||||
}
|
||||
return ObserveAsync(_baselineHandler.Handle(_reflectionRequest, CancellationToken.None), Observation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 GFramework.CQRS reflection stream binding 路径创建并完整枚举 stream。
|
||||
/// 通过 GFramework.CQRS reflection stream binding 路径创建 stream,并按当前观测模式消费。
|
||||
/// </summary>
|
||||
[Benchmark]
|
||||
public async ValueTask Stream_GFrameworkReflection()
|
||||
public ValueTask Stream_GFrameworkReflection()
|
||||
{
|
||||
await foreach (var response in _reflectionRuntime.CreateStream(
|
||||
BenchmarkContext.Instance,
|
||||
_reflectionRequest,
|
||||
CancellationToken.None)
|
||||
.ConfigureAwait(false))
|
||||
{
|
||||
_ = response;
|
||||
}
|
||||
return ObserveAsync(
|
||||
_reflectionRuntime.CreateStream(
|
||||
BenchmarkContext.Instance,
|
||||
_reflectionRequest,
|
||||
CancellationToken.None),
|
||||
Observation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 generated stream invoker provider 预热后的 GFramework.CQRS runtime 创建并完整枚举 stream。
|
||||
/// 通过 generated stream invoker provider 预热后的 GFramework.CQRS runtime 创建 stream,并按当前观测模式消费。
|
||||
/// </summary>
|
||||
[Benchmark]
|
||||
public async ValueTask Stream_GFrameworkGenerated()
|
||||
public ValueTask Stream_GFrameworkGenerated()
|
||||
{
|
||||
await foreach (var response in _generatedRuntime.CreateStream(
|
||||
BenchmarkContext.Instance,
|
||||
_generatedRequest,
|
||||
CancellationToken.None)
|
||||
.ConfigureAwait(false))
|
||||
{
|
||||
_ = response;
|
||||
}
|
||||
return ObserveAsync(
|
||||
_generatedRuntime.CreateStream(
|
||||
BenchmarkContext.Instance,
|
||||
_generatedRequest,
|
||||
CancellationToken.None),
|
||||
Observation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 MediatR 创建并完整枚举 stream,作为外部对照。
|
||||
/// 通过 MediatR 创建 stream,并按当前观测模式消费,作为外部对照。
|
||||
/// </summary>
|
||||
[Benchmark]
|
||||
public async ValueTask Stream_MediatR()
|
||||
public ValueTask Stream_MediatR()
|
||||
{
|
||||
await foreach (var response in _mediatr.CreateStream(_mediatrRequest, CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
_ = response;
|
||||
}
|
||||
return ObserveAsync(_mediatr.CreateStream(_mediatrRequest, CancellationToken.None), Observation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -271,6 +283,62 @@ public class StreamLifetimeBenchmarks
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按观测模式消费 stream,便于把“建流/首个元素”和“完整枚举”分开观察。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">当前 stream 的响应类型。</typeparam>
|
||||
/// <param name="responses">待观察的异步响应序列。</param>
|
||||
/// <param name="observation">当前 benchmark 选定的观测模式。</param>
|
||||
/// <returns>异步消费完成后的等待句柄。</returns>
|
||||
private static ValueTask ObserveAsync<TResponse>(
|
||||
IAsyncEnumerable<TResponse> responses,
|
||||
StreamObservation observation)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(responses);
|
||||
|
||||
return observation switch
|
||||
{
|
||||
StreamObservation.FirstItem => ConsumeFirstItemAsync(responses),
|
||||
StreamObservation.DrainAll => DrainAsync(responses),
|
||||
_ => throw new ArgumentOutOfRangeException(
|
||||
nameof(observation),
|
||||
observation,
|
||||
"Unsupported stream observation mode.")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 只推进到首个元素后立即释放枚举器,用来近似隔离建流与首个 `MoveNextAsync` 的固定成本。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">当前 stream 的响应类型。</typeparam>
|
||||
/// <param name="responses">待观察的异步响应序列。</param>
|
||||
/// <returns>消费首个元素后的等待句柄。</returns>
|
||||
private static async ValueTask ConsumeFirstItemAsync<TResponse>(IAsyncEnumerable<TResponse> responses)
|
||||
{
|
||||
var enumerator = responses.GetAsyncEnumerator();
|
||||
await using (enumerator.ConfigureAwait(false))
|
||||
{
|
||||
if (await enumerator.MoveNextAsync().ConfigureAwait(false))
|
||||
{
|
||||
_ = enumerator.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 完整枚举整个 stream,保留原 benchmark 的总成本观测口径。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">当前 stream 的响应类型。</typeparam>
|
||||
/// <param name="responses">待完整枚举的异步响应序列。</param>
|
||||
/// <returns>完整枚举结束后的等待句柄。</returns>
|
||||
private static async ValueTask DrainAsync<TResponse>(IAsyncEnumerable<TResponse> responses)
|
||||
{
|
||||
await foreach (var response in responses.ConfigureAwait(false))
|
||||
{
|
||||
_ = response;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reflection runtime stream request。
|
||||
/// </summary>
|
||||
|
||||
@ -60,7 +60,8 @@ dotnet run --project GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.cspro
|
||||
|
||||
- `BenchmarkDotNet.Artifacts/` 属于本地生成输出,默认加入仓库忽略,不作为常规提交内容
|
||||
- `RequestLifetimeBenchmarks` 现在复用与默认 generated-provider 路径一致的 benchmark 宿主接线;它比较的是生命周期切换后的 handler 解析与 dispatch 成本,不单独引入另一套 runtime 发现口径
|
||||
- `StreamLifetimeBenchmarks` 现在按 direct handler、`GFramework.Cqrs` reflection、`GFramework.Cqrs` generated、`MediatR` 四层口径组织,用于把 stream 生命周期成本与 binding 路径成本拆开观察
|
||||
- `StreamLifetimeBenchmarks` 现在按 direct handler、`GFramework.Cqrs` reflection、`GFramework.Cqrs` generated、`MediatR` 四层口径组织,并额外区分 `FirstItem` 与 `DrainAll` 两种观测方式,用于把 stream 建流/首个元素成本与完整枚举成本拆开观察
|
||||
- 按 `RP-127` 当前短跑结果,`StreamLifetimeBenchmarks` 在 `Singleton` 下无论 `FirstItem` 还是 `DrainAll` 都表现为 generated 略优于 reflection;在 `Transient` 下,`FirstItem` 仍是 reflection 略优于 generated,但 `DrainAll` 已转为 generated 优于 reflection。这说明当前差值主要集中在建流到首个元素之间的瞬时成本,而不是完整枚举阶段整体退化
|
||||
- 只要变更影响 `GFramework.Cqrs` request dispatch、DI 解析热路径、invoker/provider、pipeline 或 benchmark 宿主,就应至少复跑能覆盖该路径的过滤场景;request 热路径通常先看:
|
||||
- `RequestBenchmarks.SendRequest_*`
|
||||
- `RequestLifetimeBenchmarks.SendRequest_*`
|
||||
@ -71,6 +72,7 @@ dotnet run --project GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.cspro
|
||||
|
||||
## 后续扩展方向
|
||||
|
||||
- 若继续沿 `RP-127` 收口 stream lifetime,可优先复核 `Transient + FirstItem` 下 generated 与 reflection 的小幅差值是否稳定,再决定继续压 generated 宿主的建流瞬时成本,还是把后续对照切回 `StreamInvokerBenchmarks` / `Mediator` concrete runtime 批次
|
||||
- request / stream 的真实 source-generator 产物与 handwritten generated provider 对照
|
||||
- `Mediator` 的 transient / scoped compile-time lifetime 矩阵对照
|
||||
- 带真实显式作用域边界的 scoped host 对照
|
||||
|
||||
@ -7,18 +7,20 @@ CQRS 迁移与收敛。
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`CQRS-REWRITE-RP-126`
|
||||
- 恢复点编号:`CQRS-REWRITE-RP-127`
|
||||
- 当前阶段:`Phase 8`
|
||||
- 当前 PR 锚点:`PR #344`(`origin/main` 已合入)
|
||||
- 当前结论:
|
||||
- 当前 `RP-126` 延续 `$gframework-batch-boot 50`,在 `RP-124` 收口 stream behavior presence cache 后,先用 `f9c9561f` 把 `RequestLifetimeBenchmarks` 对齐到 generated-provider 宿主路径,再用 `9107e232` 把 `StreamLifetimeBenchmarks` 扩成 `baseline / GFramework reflection / GFramework generated / MediatR` 的完整生命周期对照口径
|
||||
- 本轮写面只落在 `GFramework.Cqrs.Benchmarks/Messaging/GeneratedRequestLifetimeBenchmarkRegistry.cs`、`RequestLifetimeBenchmarks.cs`、`GeneratedStreamLifetimeBenchmarkRegistry.cs`、`StreamLifetimeBenchmarks.cs`,以及 `ai-plan/public/cqrs-rewrite` 恢复文档,不回改 runtime、测试或 README
|
||||
- 当前 `RP-127` 延续 `$gframework-batch-boot 50`,在 `RP-126` 已补齐 stream lifetime 四方口径后,再用 `b7fa3eee` 把 `CqrsDispatcher.CreateStream(...)` 的 stream dispatch binding 改为按 `TResponse` 强类型缓存,同时为 `StreamLifetimeBenchmarks` 增加 `FirstItem / DrainAll` 观测维度,并把新的结果回填到公开可恢复文档
|
||||
- 本轮写面落在 `GFramework.Cqrs/Internal/CqrsDispatcher.cs`、`GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs`、`GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs`、`GFramework.Cqrs.Benchmarks/Messaging/StreamLifetimeBenchmarks.cs`,以及 `GFramework.Cqrs.Benchmarks/README.md` / `ai-plan/public/cqrs-rewrite/**` 恢复文档;没有扩散到 request runtime、notification runtime 或额外文档模块
|
||||
- `f9c9561f` 为 request lifetime 补入 handwritten generated registry,并在 setup/cleanup 清理 dispatcher cache;这样 `Singleton / Transient` 生命周期矩阵继续只比较 handler 生命周期与 dispatch 常量路径,不再混入旧宿主差异
|
||||
- `9107e232` 将 stream lifetime 的 reflection、generated 与 `MediatR` 请求/响应/handler 彻底拆开,并限制 generated registry 只绑定 generated lane,避免静态 dispatcher cache 把不同 stream 对照口径污染到一起
|
||||
- 当前 request lifetime benchmark 已用新宿主重新验证:`Singleton` 下 baseline / `GFramework.Cqrs` / `MediatR` 约为 `5.012 ns / 32 B`、`49.612 ns / 32 B`、`51.796 ns / 232 B`;`Transient` 下约为 `3.962 ns / 32 B`、`50.480 ns / 56 B`、`50.284 ns / 232 B`
|
||||
- 当前 stream lifetime benchmark 已产出完整四方结果:`Singleton` 下 baseline / generated / reflection / `MediatR` 约为 `79.602 ns / 280 B`、`111.547 ns / 280 B`、`120.553 ns / 280 B`、`208.381 ns / 672 B`;`Transient` 下 baseline / reflection / generated / `MediatR` 约为 `76.351 ns / 280 B`、`119.632 ns / 304 B`、`129.166 ns / 304 B`、`213.420 ns / 672 B`
|
||||
- 当前已提交分支相对 `origin/main`(`d85828c5`, `2026-05-09 12:25:41 +0800`)的累计 branch diff 已到 `10 files`(`556 insertions / 75 deletions`),仍远低于 `$gframework-batch-boot 50` 的 `50 files` stop condition
|
||||
- 下一推荐步骤:若继续 benchmark 线,先以 `RP-126` 的四方 stream lifetime 口径判断是否要追 `Generated` 在 `Transient` 下仍慢于 `Reflection` 的差值,再决定继续压 stream transient 常量路径,还是单开 `Mediator` concrete runtime 的 stream lifetime 对照批次;若切回 runtime 线,则以 `RP-125` / `RP-126` 结果作为后续性能回归基线
|
||||
- 当前 stream lifetime benchmark 已更新为 `Observation=FirstItem / DrainAll` 双口径:`Singleton + FirstItem` 下 baseline / generated / reflection / `MediatR` 约为 `48.704 ns / 216 B`、`94.629 ns / 216 B`、`95.417 ns / 216 B`、`152.886 ns / 608 B`;`Singleton + DrainAll` 下约为 `73.335 ns / 280 B`、`118.860 ns / 280 B`、`119.632 ns / 280 B`、`205.629 ns / 672 B`
|
||||
- `Transient + FirstItem` 下 baseline / reflection / generated / `MediatR` 约为 `48.293 ns / 216 B`、`97.628 ns / 240 B`、`100.011 ns / 240 B`、`154.149 ns / 608 B`;`Transient + DrainAll` 下约为 `78.466 ns / 280 B`、`124.174 ns / 304 B`、`116.780 ns / 304 B`、`220.040 ns / 672 B`
|
||||
- 现阶段可恢复结论收口为三点:一是 stream lifetime 已具备四方口径加 `FirstItem / DrainAll` 双观测维度;二是 `b7fa3eee` 已让 generated lane 在 `DrainAll` 口径下重新领先 reflection;三是 `Transient + FirstItem` 仍保留约 `2.4 ns` 的小幅反向差值,更像建流到首个元素之间的瞬时成本,而不是完整枚举阶段退化
|
||||
- 当前已提交分支相对 `origin/main`(`d85828c5`, `2026-05-09 12:25:41 +0800`)的累计 branch diff 已到 `21 files`(`1231 insertions / 181 deletions`),仍明显低于 `$gframework-batch-boot 50` 的 `50 files` stop condition
|
||||
- 下一推荐步骤:若继续 benchmark 线,优先从 `StreamLifetimeBenchmarks` 的 `Transient + FirstItem` 小幅差值继续恢复,并用 `StreamInvokerBenchmarks` 复核 generated lane 的常量成本收益是否能在更窄口径下复现;若差值不再稳定,再决定是否转去 `Mediator` concrete runtime 的 stream lifetime 对照批次
|
||||
- 更早的 `RP-123` 及之前阶段细节以下方 trace 与归档为准,active 入口不再重复展开旧阶段流水。
|
||||
- 当前分支相对 `origin/main` 的累计 branch diff 启动时为 `9 files`,仍明显低于 `$gframework-batch-boot 50` 的停止阈值;这一批继续保持单模块、低风险、可直接评审的 benchmark 边界
|
||||
- 当前 `RP-113` 已继续沿用 `$gframework-batch-boot 50`,并把 notification 线从 benchmark 对照推进到实际 runtime 能力:新增公开内置 `TaskWhenAllNotificationPublisher`,让 `GFramework.Cqrs` 在保留默认顺序发布器的同时,提供与 `Mediator` `TaskWhenAllPublisher` 对齐的并行 notification publish 策略
|
||||
|
||||
@ -2,6 +2,34 @@
|
||||
|
||||
## 2026-05-09
|
||||
|
||||
### 阶段:stream lifetime 观测维度补齐与 generated binding 强类型缓存(CQRS-REWRITE-RP-127)
|
||||
|
||||
- 延续 `$gframework-batch-boot 50`,在 `RP-126` 已建立四方 stream lifetime 口径后,本轮改用多 worker wave 同时推进三个互不冲突切片:
|
||||
- `benchmark-only`:为 `StreamLifetimeBenchmarks` 增加 `FirstItem / DrainAll` 观测维度,并收口 `MA0004`
|
||||
- `runtime-only`:把 `CqrsDispatcher.CreateStream(...)` 的 stream dispatch binding 改成按 `TResponse` 强类型缓存,避免 generated lane 在热路径上继续通过 `object -> IAsyncEnumerable<TResponse>` 桥接
|
||||
- `docs / ai-plan`:把 `RP-126` 的旧恢复结论更新为本轮实测结果,并给出下一恢复入口
|
||||
- 本轮主线程验收与修正:
|
||||
- 首次并行验证时,`dotnet test` 与 `dotnet build` 同跑触发 `MSB3030` 输出争用;已按仓库规则改为串行重跑同一命令,并以串行结果为权威
|
||||
- runtime worker 初版在 `CqrsDispatcher.cs` 留下一个 `StreamInvoker<TResponse>` 方法组绑定编译错误;主线程已局部修正为显式 lambda 适配,未改变预期语义
|
||||
- 经修正后,generated lane 不再出现 “incompatible invoker signature” 运行时异常,`StreamLifetimeBenchmarks` 16 个 case 全部通过
|
||||
- 本轮验证:
|
||||
- `dotnet build GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release`
|
||||
- 结果:通过,`0 warning / 0 error`
|
||||
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
|
||||
- 结果:通过,`0 warning / 0 error`
|
||||
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsDispatcherCacheTests|FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests"`
|
||||
- 结果:通过,`31/31` passed
|
||||
- `dotnet run --project GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release --no-build -- --filter "*StreamLifetimeBenchmarks*" --job short --warmupCount 1 --iterationCount 1 --launchCount 1`
|
||||
- 结果:通过
|
||||
- 备注:`Transient + FirstItem` 下 generated 约 `100.011 ns / 240 B`、reflection 约 `97.628 ns / 240 B`;`Transient + DrainAll` 下 generated 约 `116.780 ns / 304 B`、reflection 约 `124.174 ns / 304 B`
|
||||
- 本轮结论:
|
||||
- `FirstItem / DrainAll` 双观测维度把“建流到首个元素的瞬时成本”和“完整枚举总成本”拆开后,`Transient` 场景下的 generated lane 已不再呈现统一的反向退化
|
||||
- 当前仍保留的差值集中在 `Transient + FirstItem`,规模约 `2.4 ns`,明显小于 `RP-126` 的旧结论;而 `Transient + DrainAll` 已转为 generated 领先 reflection
|
||||
- 当前分支相对 `origin/main` 的累计 branch diff 已到 `21 files`(`1231 insertions / 181 deletions`),仍低于 `$gframework-batch-boot 50` 阈值;但主线程已接近当前回合的安全上下文预算,因此在本轮自然边界停止,不继续开下一波 worker
|
||||
- 下一恢复点:
|
||||
- 若继续 benchmark 线,先从 `Transient + FirstItem` 的小幅差值恢复,并用 `StreamInvokerBenchmarks` 复核 generated lane 的常量成本收益是否仍成立;若差值不稳定,再考虑把下一批切到 `Mediator` concrete runtime 的 stream lifetime 对照
|
||||
- 若切回 runtime 线,则以 `b7fa3eee` 与本轮 `StreamLifetimeBenchmarks` 双口径结果作为后续回归基线
|
||||
|
||||
### 阶段:stream lifetime 对照口径补齐(CQRS-REWRITE-RP-126)
|
||||
|
||||
- 延续 `$gframework-batch-boot 50`,在 `RP-125` 先把 request lifetime benchmark 宿主对齐到 generated-provider 路径后,本轮继续补齐 stream 生命周期矩阵的当前对照口径,不回到 runtime 或测试代码
|
||||
@ -16,11 +44,11 @@
|
||||
- 结果:通过
|
||||
- 备注:`Singleton` 下 baseline / generated / reflection / `MediatR` 约为 `79.602 ns / 280 B`、`111.547 ns / 280 B`、`120.553 ns / 280 B`、`208.381 ns / 672 B`;`Transient` 下 baseline / reflection / generated / `MediatR` 约为 `76.351 ns / 280 B`、`119.632 ns / 304 B`、`129.166 ns / 304 B`、`213.420 ns / 672 B`
|
||||
- 本轮结论:
|
||||
- 当前 stream 生命周期矩阵已经从“单看 `GFramework.Cqrs` 一条线是否还能跑通”升级为可直接比较 `baseline / reflection / generated / MediatR` 的四方口径
|
||||
- 当前短跑下,generated lane 在 `Singleton` 档优于 reflection,但在 `Transient` 档仍慢于 reflection;这说明后续若继续压 stream 热点,应该围绕 generated 宿主的瞬时解析成本继续定位,而不是回头重做已经分离完成的对照口径
|
||||
- 当前 stream 生命周期矩阵已经具备可直接比较 `baseline / reflection / generated / MediatR` 的四方口径,后续恢复时无需再回头拼接不同批次的 stream 生命周期数据
|
||||
- 当前短跑下,generated lane 在 `Singleton` 档优于 reflection,但在 `Transient` 档仍慢于 reflection,差值约为 `9.5 ns` 与 `24 B`;这里先只把它记录为 benchmark 观察,不把它放大成更宽泛的 runtime 优劣结论
|
||||
- 当前已提交分支相对 `origin/main`(`d85828c5`, `2026-05-09 12:25:41 +0800`)的累计 branch diff 已到 `10 files`(`556 insertions / 75 deletions`),仍远低于 `$gframework-batch-boot 50` 的 `50 files` stop condition
|
||||
- 下一恢复点:
|
||||
- 若继续 benchmark 线,优先判断是否要追 `Stream_GFrameworkGenerated` 在 `Transient` 下仍慢于 `Stream_GFrameworkReflection` 的差值,或单开 `Mediator` concrete runtime 的 stream lifetime 对照批次;若切回 runtime 线,则以 `RP-126` 的四方矩阵作为后续性能回归基线
|
||||
- 若继续 benchmark 线,优先从 `Stream_GFrameworkGenerated` 与 `Stream_GFrameworkReflection` 的 `Transient` 差值恢复,先确认该差值是否稳定,再决定继续压 generated 宿主的瞬时解析成本,或单开 `Mediator` concrete runtime 的 stream lifetime 对照批次;若切回 runtime 线,则以 `RP-126` 的四方矩阵作为后续性能回归基线
|
||||
|
||||
### 阶段:request lifetime generated-provider 宿主对齐(CQRS-REWRITE-RP-125)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user