refactor(coroutine): 优化协程调度器中的暂停计数统计

- 引入 _pausedCount 字段直接跟踪暂停协程数量
- 将统计信息中的 ActiveCount 和 PausedCount 改为线程安全的原子操作
- 在暂停和恢复协程时直接更新 _pausedCount 计数
- 修复 KillGroup 方法中的并发修改异常问题
- 重置统计信息时使用原子操作清零计数字段
This commit is contained in:
GeWuYou 2026-03-06 12:59:05 +08:00
parent 06114db8bd
commit 74f27ddfd5
2 changed files with 21 additions and 6 deletions

View File

@ -27,6 +27,7 @@ public sealed class CoroutineScheduler(
private readonly ITimeSource _timeSource = timeSource ?? throw new ArgumentNullException(nameof(timeSource)); private readonly ITimeSource _timeSource = timeSource ?? throw new ArgumentNullException(nameof(timeSource));
private readonly Dictionary<CoroutineHandle, HashSet<CoroutineHandle>> _waiting = new(); private readonly Dictionary<CoroutineHandle, HashSet<CoroutineHandle>> _waiting = new();
private int _nextSlot; private int _nextSlot;
private int _pausedCount;
private CoroutineSlot?[] _slots = new CoroutineSlot?[initialCapacity]; private CoroutineSlot?[] _slots = new CoroutineSlot?[initialCapacity];
@ -133,7 +134,7 @@ public sealed class CoroutineScheduler(
if (_statistics != null) if (_statistics != null)
{ {
_statistics.ActiveCount = ActiveCoroutineCount; _statistics.ActiveCount = ActiveCoroutineCount;
_statistics.PausedCount = _metadata.Count(m => m.Value.State == CoroutineState.Paused); _statistics.PausedCount = _pausedCount;
} }
// 按优先级排序槽位索引(高优先级优先执行) // 按优先级排序槽位索引(高优先级优先执行)
@ -264,6 +265,7 @@ public sealed class CoroutineScheduler(
slot.State = CoroutineState.Paused; slot.State = CoroutineState.Paused;
meta.State = CoroutineState.Paused; meta.State = CoroutineState.Paused;
_pausedCount++;
return true; return true;
} }
@ -283,6 +285,7 @@ public sealed class CoroutineScheduler(
slot.State = CoroutineState.Running; slot.State = CoroutineState.Running;
meta.State = CoroutineState.Running; meta.State = CoroutineState.Running;
_pausedCount--;
return true; return true;
} }
@ -340,7 +343,8 @@ public sealed class CoroutineScheduler(
if (!_grouped.TryGetValue(group, out var handles)) if (!_grouped.TryGetValue(group, out var handles))
return 0; return 0;
return handles.Count(Kill); var copy = handles.ToArray();
return copy.Count(Kill);
} }
/// <summary> /// <summary>
@ -409,6 +413,7 @@ public sealed class CoroutineScheduler(
_nextSlot = 0; _nextSlot = 0;
ActiveCoroutineCount = 0; ActiveCoroutineCount = 0;
_pausedCount = 0;
return count; return count;
} }

View File

@ -12,7 +12,9 @@ internal sealed class CoroutineStatistics : ICoroutineStatistics
private readonly Dictionary<CoroutinePriority, int> _countByPriority = new(); private readonly Dictionary<CoroutinePriority, int> _countByPriority = new();
private readonly Dictionary<string, int> _countByTag = new(); private readonly Dictionary<string, int> _countByTag = new();
private readonly object _lock = new(); private readonly object _lock = new();
private int _activeCount;
private double _maxExecutionTimeMs; private double _maxExecutionTimeMs;
private int _pausedCount;
private long _totalCompleted; private long _totalCompleted;
private long _totalExecutionTimeMs; private long _totalExecutionTimeMs;
private long _totalFailed; private long _totalFailed;
@ -28,10 +30,18 @@ internal sealed class CoroutineStatistics : ICoroutineStatistics
public long TotalFailed => Interlocked.Read(ref _totalFailed); public long TotalFailed => Interlocked.Read(ref _totalFailed);
/// <inheritdoc /> /// <inheritdoc />
public int ActiveCount { get; set; } public int ActiveCount
{
get => Interlocked.CompareExchange(ref _activeCount, 0, 0);
set => Interlocked.Exchange(ref _activeCount, value);
}
/// <inheritdoc /> /// <inheritdoc />
public int PausedCount { get; set; } public int PausedCount
{
get => Interlocked.CompareExchange(ref _pausedCount, 0, 0);
set => Interlocked.Exchange(ref _pausedCount, value);
}
/// <inheritdoc /> /// <inheritdoc />
public double AverageExecutionTimeMs public double AverageExecutionTimeMs
@ -84,14 +94,14 @@ internal sealed class CoroutineStatistics : ICoroutineStatistics
Interlocked.Exchange(ref _totalCompleted, 0); Interlocked.Exchange(ref _totalCompleted, 0);
Interlocked.Exchange(ref _totalFailed, 0); Interlocked.Exchange(ref _totalFailed, 0);
Interlocked.Exchange(ref _totalExecutionTimeMs, 0); Interlocked.Exchange(ref _totalExecutionTimeMs, 0);
Interlocked.Exchange(ref _activeCount, 0);
Interlocked.Exchange(ref _pausedCount, 0);
lock (_lock) lock (_lock)
{ {
_maxExecutionTimeMs = 0; _maxExecutionTimeMs = 0;
_countByPriority.Clear(); _countByPriority.Clear();
_countByTag.Clear(); _countByTag.Clear();
ActiveCount = 0;
PausedCount = 0;
} }
} }