using System; using System.Diagnostics; using System.Reflection; using System.Text; using Cysharp.Threading.Tasks; using UnityEngine; using Debug = UnityEngine.Debug; namespace ShrinkEventBus.Runtime { /// /// ShrinkEventBus 性能测试。 /// 挂在任意 GameObject 上,运行后在 Console 查看结果。 /// 在进行测试时不要打开事件查看器的大量实时追踪。 /// public sealed class EventBusBenchmark : MonoBehaviour { [Header("同步触发测试")] public int iterations = 1_000_000; [Header("大批量订阅者测试")] public int subscriberCount = 30; public int massIterations = 10_000; [Header("异步触发测试")] public int asyncIterations = 1_000; [Header("注册 / 注销测试")] public int registerIterations = 5_000; public int scannedRegisterIterations = 1_000; [Header("取消事件测试")] public int cancelIterations = 100_000; public class BenchmarkEvent : EventBase { public int Value { get; set; } } public sealed class DerivedBenchmarkEvent : BenchmarkEvent { public bool IsDerived { get; set; } } [Cancelable] public class CancelableBenchmarkEvent : EventBase { public int Value { get; set; } } private sealed class BenchmarkInstanceSubscriber { public int Recorded; [EventSubscribe(EventPriority.NORMAL)] private void OnBenchmark(BenchmarkEvent evt) { Recorded = evt.Value; } } private static class BenchmarkStaticSubscriber { public static int Recorded; [EventSubscribe(EventPriority.NORMAL)] private static void OnBenchmark(BenchmarkEvent evt) { Recorded = evt.Value; } } private static class BenchmarkMethodSubscriber { public static int Recorded; [EventSubscribe(EventPriority.NORMAL)] private static void OnBenchmark(BenchmarkEvent evt) { Recorded = evt.Value; } } private sealed class PhaseSubscriber { public int Sum; [EventSubscribe(EventPriority.HIGH)] private void OnHigh(BenchmarkEvent evt) { Sum += evt.Value + 1; } [EventSubscribe(EventPriority.NORMAL)] private void OnNormal(BenchmarkEvent evt) { Sum += evt.Value + 10; } [EventSubscribe(EventPriority.LOW)] private void OnLow(BenchmarkEvent evt) { Sum += evt.Value + 100; } } private readonly StringBuilder _report = new(); private void Start() { RunAllBenchmarks().Forget(); } private async UniTaskVoid RunAllBenchmarks() { _report.Clear(); _report.AppendLine("╔══════════════════════════════════════════════════╗"); _report.AppendLine("║ ShrinkEventBus Benchmark Report ║"); _report.AppendLine( $"║ iter={iterations,8} mass={massIterations,6} reg={registerIterations,5} scan={scannedRegisterIterations,4} ║"); _report.AppendLine("╚══════════════════════════════════════════════════╝"); _report.AppendLine(" 基准对象:独立实例 bus(AllowPerPhaseDispatch 已开启)"); Log("开始:无订阅者触发"); Bench_TriggerEvent_NoSubscriber(); await UniTask.Yield(); Log("开始:单订阅者同步触发"); Bench_TriggerEvent_SingleSubscriber(); await UniTask.Yield(); Log("开始:父事件监听子事件"); Bench_TriggerEvent_InheritedSubscriber(); await UniTask.Yield(); Log($"开始:{subscriberCount} 订阅者同步触发"); Bench_TriggerEvent_MassSubscribers(); await UniTask.Yield(); Log("开始:按 phase 分发"); Bench_TriggerEvent_PerPhase(); await UniTask.Yield(); Log("开始:异步触发"); await Bench_TriggerEventAsync(); await UniTask.Yield(); Log("开始:手工 delegate 注册/注销"); Bench_RegisterUnregister_ManualDelegate(); await UniTask.Yield(); Log("开始:实例扫描注册/注销"); Bench_RegisterUnregister_InstanceScan(); await UniTask.Yield(); Log("开始:静态类型扫描注册/注销"); Bench_RegisterUnregister_StaticScan(); await UniTask.Yield(); Log("开始:MethodInfo 注册/注销"); Bench_RegisterUnregister_MethodScan(); await UniTask.Yield(); Log("开始:EventPool vs new"); Bench_EventPool_vs_New(); await UniTask.Yield(); Log("开始:已取消事件跳过"); Bench_CanceledEvent_Skip(); _report.AppendLine("\n══════════════════════════════════════════════════"); _report.AppendLine(" 全部测试完成"); Debug.Log(_report.ToString()); } private void Bench_TriggerEvent_NoSubscriber() { var bus = CreateBenchmarkBus(); var evt = new BenchmarkEvent { Value = 1 }; Warmup(() => bus.TriggerEvent(evt), 500); var sw = Stopwatch.StartNew(); for (var i = 0; i < iterations; i++) bus.TriggerEvent(evt); sw.Stop(); Record("TriggerEvent × 无订阅者(基线)", sw.Elapsed.TotalMilliseconds, iterations); Log("完成:无订阅者触发"); } private void Bench_TriggerEvent_SingleSubscriber() { var bus = CreateBenchmarkBus(); var dummy = 0; void Handler(BenchmarkEvent evt) { dummy = evt.Value; } bus.RegisterEvent(Handler, EventPriority.NORMAL); var evt = new BenchmarkEvent { Value = 1 }; Warmup(() => bus.TriggerEvent(evt), 500); var sw = Stopwatch.StartNew(); for (var i = 0; i < iterations; i++) bus.TriggerEvent(evt); sw.Stop(); Record("TriggerEvent × 单订阅者同步", sw.Elapsed.TotalMilliseconds, iterations); Log("完成:单订阅者同步触发"); bus.UnregisterEvent(Handler); GC.KeepAlive(dummy); } private void Bench_TriggerEvent_InheritedSubscriber() { var bus = CreateBenchmarkBus(); var dummy = 0; void Handler(BenchmarkEvent evt) { dummy = evt.Value; } bus.RegisterEvent(Handler, EventPriority.NORMAL); var evt = new DerivedBenchmarkEvent { Value = 1, IsDerived = true }; Warmup(() => bus.TriggerEvent(evt), 500); var sw = Stopwatch.StartNew(); for (var i = 0; i < iterations; i++) bus.TriggerEvent(evt); sw.Stop(); Record("TriggerEvent × 父事件监听子事件", sw.Elapsed.TotalMilliseconds, iterations); Log("完成:父事件监听子事件"); bus.UnregisterEvent(Handler); GC.KeepAlive(dummy); } private void Bench_TriggerEvent_MassSubscribers() { var bus = CreateBenchmarkBus(); var dummy = 0; var handlers = new Action[subscriberCount]; for (var i = 0; i < subscriberCount; i++) { var captured = i; handlers[i] = evt => { dummy = captured + evt.Value; }; bus.RegisterEvent(handlers[i], EventPriority.NORMAL); } var evt = new BenchmarkEvent { Value = 1 }; Warmup(() => bus.TriggerEvent(evt), 100); var sw = Stopwatch.StartNew(); for (var i = 0; i < massIterations; i++) bus.TriggerEvent(evt); sw.Stop(); Record($"TriggerEvent × {subscriberCount} 订阅者同步", sw.Elapsed.TotalMilliseconds, massIterations); Log($"完成:{subscriberCount} 订阅者同步触发"); foreach (var handler in handlers) bus.UnregisterEvent(handler); GC.KeepAlive(dummy); } private void Bench_TriggerEvent_PerPhase() { var bus = CreateBenchmarkBus(); var subscriber = new PhaseSubscriber(); bus.Register(subscriber); var evt = new BenchmarkEvent { Value = 1 }; Warmup(() => bus.TriggerEvent(EventPriority.HIGH, evt), 500); var sw = Stopwatch.StartNew(); for (var i = 0; i < iterations; i++) bus.TriggerEvent(EventPriority.HIGH, evt); sw.Stop(); Record("TriggerEvent(Phase=HIGH) × 3 phase 监听", sw.Elapsed.TotalMilliseconds, iterations); Log("完成:按 phase 分发"); bus.Unregister(subscriber); GC.KeepAlive(subscriber.Sum); } private async UniTask Bench_TriggerEventAsync() { var bus = CreateBenchmarkBus(); var dummy = 0; async UniTask Handler(BenchmarkEvent evt) { dummy = evt.Value; await UniTask.CompletedTask; } bus.RegisterEvent(Handler, EventPriority.NORMAL); var evt = new BenchmarkEvent { Value = 1 }; await WarmupAsync(() => bus.TriggerEventAsync(evt), 10); const int perFrame = 10; var totalMs = 0.0; var ran = 0; while (ran < asyncIterations) { await UniTask.Yield(); var count = Math.Min(perFrame, asyncIterations - ran); var sw = Stopwatch.StartNew(); for (var i = 0; i < count; i++) await bus.TriggerEventAsync(evt); sw.Stop(); totalMs += sw.Elapsed.TotalMilliseconds; ran += count; } Record("TriggerEventAsync × 单订阅者异步", totalMs, asyncIterations); Log("完成:异步触发"); bus.UnregisterEvent(Handler); GC.KeepAlive(dummy); } private void Bench_RegisterUnregister_ManualDelegate() { var bus = CreateBenchmarkBus(); var dummy = 0; var handlers = new Action[registerIterations]; for (var i = 0; i < registerIterations; i++) { var captured = i; handlers[i] = evt => { dummy = captured; }; } var swReg = Stopwatch.StartNew(); for (var i = 0; i < registerIterations; i++) bus.RegisterEvent(handlers[i], EventPriority.NORMAL); swReg.Stop(); Record("RegisterEvent(delegate)", swReg.Elapsed.TotalMilliseconds, registerIterations); var swUnreg = Stopwatch.StartNew(); for (var i = 0; i < registerIterations; i++) bus.UnregisterEvent(handlers[i]); swUnreg.Stop(); Record("UnregisterEvent(delegate)", swUnreg.Elapsed.TotalMilliseconds, registerIterations); Log("完成:手工 delegate 注册/注销"); GC.KeepAlive(dummy); } private void Bench_RegisterUnregister_InstanceScan() { var bus = CreateBenchmarkBus(); var subscribers = new BenchmarkInstanceSubscriber[scannedRegisterIterations]; for (var i = 0; i < subscribers.Length; i++) subscribers[i] = new BenchmarkInstanceSubscriber(); var sw = Stopwatch.StartNew(); for (var i = 0; i < subscribers.Length; i++) { var subscriber = subscribers[i]; bus.Register(subscriber); bus.Unregister(subscriber); } sw.Stop(); Record("Register/Unregister(instance scan)", sw.Elapsed.TotalMilliseconds, subscribers.Length); Log("完成:实例扫描注册/注销"); } private void Bench_RegisterUnregister_StaticScan() { var bus = CreateBenchmarkBus(); var sw = Stopwatch.StartNew(); for (var i = 0; i < scannedRegisterIterations; i++) { bus.Register(typeof(BenchmarkStaticSubscriber)); bus.Unregister(typeof(BenchmarkStaticSubscriber)); } sw.Stop(); Record("Register/Unregister(static type scan)", sw.Elapsed.TotalMilliseconds, scannedRegisterIterations); Log("完成:静态类型扫描注册/注销"); } private void Bench_RegisterUnregister_MethodScan() { var bus = CreateBenchmarkBus(); var method = typeof(BenchmarkMethodSubscriber).GetMethod("OnBenchmark", BindingFlags.Static | BindingFlags.NonPublic); if (method == null) throw new MissingMethodException(typeof(BenchmarkMethodSubscriber).FullName, "OnBenchmark"); var sw = Stopwatch.StartNew(); for (var i = 0; i < scannedRegisterIterations; i++) { bus.Register(method); bus.Unregister(method); } sw.Stop(); Record("Register/Unregister(MethodInfo)", sw.Elapsed.TotalMilliseconds, scannedRegisterIterations); Log("完成:MethodInfo 注册/注销"); } private void Bench_EventPool_vs_New() { var bus = CreateBenchmarkBus(); void Handler(BenchmarkEvent evt) { } bus.RegisterEvent(Handler, EventPriority.NORMAL); for (var i = 0; i < 64; i++) EventPool.Release(EventPool.Get()); GC.Collect(); var gcBefore = GC.CollectionCount(0); var swNew = Stopwatch.StartNew(); for (var i = 0; i < iterations; i++) { var evt = new BenchmarkEvent { Value = i }; bus.TriggerEvent(evt); } swNew.Stop(); var gcNew = GC.CollectionCount(0) - gcBefore; Record($"TriggerEvent × new() [GC Gen0={gcNew,3}]", swNew.Elapsed.TotalMilliseconds, iterations); GC.Collect(); gcBefore = GC.CollectionCount(0); var swPool = Stopwatch.StartNew(); for (var i = 0; i < iterations; i++) { using var evt = EventPool.Get(); evt.Value = i; bus.TriggerEvent(evt); } swPool.Stop(); var gcPool = GC.CollectionCount(0) - gcBefore; Record($"TriggerEvent × Pool.Get() [GC Gen0={gcPool,3}]", swPool.Elapsed.TotalMilliseconds, iterations); Log("完成:EventPool vs new"); bus.UnregisterEvent(Handler); } private void Bench_CanceledEvent_Skip() { var bus = CreateBenchmarkBus(); var dummy = 0; var handlers = new Action[10]; for (var i = 0; i < handlers.Length; i++) { handlers[i] = evt => { dummy = evt.Value; }; bus.RegisterEvent(handlers[i], EventPriority.NORMAL); } var evt = new CancelableBenchmarkEvent { Value = 1 }; evt.SetCanceled(true); Warmup(() => bus.TriggerEvent(evt), 500); var sw = Stopwatch.StartNew(); for (var i = 0; i < cancelIterations; i++) bus.TriggerEvent(evt); sw.Stop(); Record("TriggerEvent × 已取消事件跳过(10 订阅者)", sw.Elapsed.TotalMilliseconds, cancelIterations); Log("完成:已取消事件跳过"); foreach (var handler in handlers) bus.UnregisterEvent(handler); GC.KeepAlive(dummy); } private static IShrinkEventBus CreateBenchmarkBus() { return EventBus.CreateBus(builder => builder.AllowPerPhaseDispatch()); } private static void Warmup(Action action, int count) { for (var i = 0; i < count; i++) action(); } private static async UniTask WarmupAsync(Func> action, int count) { for (var i = 0; i < count; i++) await action(); } private static void Log(string msg) { Debug.Log($"[Benchmark] {msg}"); } private void Record(string label, double totalMs, int count) { var perOp = totalMs / count * 1000.0; var throughput = totalMs <= 0.0001 ? 0 : count / (totalMs / 1000.0); _report.AppendLine($"\n ▶ {label}"); _report.AppendLine($" 总耗时 : {totalMs,10:F3} ms"); _report.AppendLine($" 单次 : {perOp,10:F4} μs/op"); _report.AppendLine($" 吞吐量 : {throughput,10:F0} ops/s"); } } }