From f64289406f0ca1a6a7e0ed1859d598ec83897211 Mon Sep 17 00:00:00 2001 From: cneicy Date: Sun, 8 Mar 2026 16:57:30 +0800 Subject: [PATCH] perf: ListenerList --- Runtime/EventBus.cs | 2 +- Runtime/ListenerList.cs | 109 ++++++++++++++++++++++++---------------- package.json | 2 +- 3 files changed, 68 insertions(+), 45 deletions(-) diff --git a/Runtime/EventBus.cs b/Runtime/EventBus.cs index 8911f3b..ef80ff6 100644 --- a/Runtime/EventBus.cs +++ b/Runtime/EventBus.cs @@ -10,7 +10,7 @@ namespace ShrinkEventBus public static class EventBus { #if UNITY_EDITOR - public static bool EnableDebugRecord { get; set; } = true; + public static bool EnableDebugRecord { get; set; } public static event Action OnEventTriggeredForEditor; #endif diff --git a/Runtime/ListenerList.cs b/Runtime/ListenerList.cs index 0caeab0..4336db7 100644 --- a/Runtime/ListenerList.cs +++ b/Runtime/ListenerList.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.Collections.Generic; using System.Reflection; namespace ShrinkEventBus @@ -7,90 +8,112 @@ namespace ShrinkEventBus public class ListenerList { private readonly object _lock = new(); - private EventHandlerInfo[] _handlers = Array.Empty(); + + private readonly List _list = new(); + + private EventHandlerInfo[] _snapshot = Array.Empty(); + private bool _dirty; + public void Add(Delegate handler, EventPriority priority, int numericPriority, bool receiveCanceled, string debugInfo = "", MethodInfo? originalMethod = null) { + var newInfo = new EventHandlerInfo(handler, priority, numericPriority, + receiveCanceled, debugInfo, originalMethod); + lock (_lock) { - var newInfo = new EventHandlerInfo(handler, priority, numericPriority, - receiveCanceled, debugInfo, originalMethod); - var newArray = new EventHandlerInfo[_handlers.Length + 1]; - Array.Copy(_handlers, newArray, _handlers.Length); - newArray[^1] = newInfo; - Array.Sort(newArray, CompareHandlers); - _handlers = newArray; + var index = BinarySearchInsertIndex(priority, numericPriority); + _list.Insert(index, newInfo); + _dirty = true; } } + public bool Remove(Delegate handler) { lock (_lock) { - var index = -1; - for (var i = 0; i < _handlers.Length; i++) + for (var i = 0; i < _list.Count; i++) { - if (_handlers[i].Handler.Equals(handler)) + if (_list[i].Handler.Equals(handler)) { - index = i; - break; + _list.RemoveAt(i); + _dirty = true; + return true; } } - - if (index == -1) return false; - - var newArray = new EventHandlerInfo[_handlers.Length - 1]; - if (index > 0) Array.Copy(_handlers, 0, newArray, 0, index); - if (index < _handlers.Length - 1) - Array.Copy(_handlers, index + 1, newArray, index, _handlers.Length - index - 1); - _handlers = newArray; - return true; + return false; } } + public void RemoveTarget(object target) { lock (_lock) { - var removeCount = 0; - for (var i = 0; i < _handlers.Length; i++) + var removed = false; + for (var i = _list.Count - 1; i >= 0; i--) { - if (_handlers[i].Target == target) removeCount++; - } - - if (removeCount == 0) return; - - var newArray = new EventHandlerInfo[_handlers.Length - removeCount]; - var dst = 0; - for (var i = 0; i < _handlers.Length; i++) - { - if (_handlers[i].Target != target) + if (_list[i].Target == target) { - newArray[dst++] = _handlers[i]; + _list.RemoveAt(i); + removed = true; } } - - _handlers = newArray; + if (removed) _dirty = true; } } - public EventHandlerInfo[] GetHandlers() => _handlers; + public EventHandlerInfo[] GetHandlers() + { + lock (_lock) + { + if (_dirty) + { + _snapshot = _list.ToArray(); + _dirty = false; + } + return _snapshot; + } + } - public int Count => _handlers.Length; + public int Count + { + get { lock (_lock) return _list.Count; } + } public void Clear() { lock (_lock) { - _handlers = Array.Empty(); + _list.Clear(); + _snapshot = Array.Empty(); + _dirty = false; } } - private static int CompareHandlers(EventHandlerInfo a, EventHandlerInfo b) + private int BinarySearchInsertIndex(EventPriority priority, int numericPriority) { - var priorityCompare = a.Priority.CompareTo(b.Priority); - return priorityCompare != 0 ? priorityCompare : b.NumericPriority.CompareTo(a.NumericPriority); + var lo = 0; + var hi = _list.Count; + + while (lo < hi) + { + var mid = (lo + hi) >> 1; + var existing = _list[mid]; + var cmp = existing.Priority.CompareTo(priority); + + if (cmp == 0) + cmp = numericPriority.CompareTo(existing.NumericPriority); // 降序 + + if (cmp < 0) + lo = mid + 1; + else + hi = mid; + } + + return lo; } } } \ No newline at end of file diff --git a/package.json b/package.json index cb714af..8afedf7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.cneicy.shrink-eventbus", - "version": "1.0.0", + "version": "1.1.0", "displayName": "ShrinkEventBus", "description": "高性能、类型安全的 Unity 事件总线,支持优先级调度与自动注册。", "unity": "2022.3",