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 Dictionary<CoroutineHandle, HashSet<CoroutineHandle>> _waiting = new();
private int _nextSlot;
private int _pausedCount;
private CoroutineSlot?[] _slots = new CoroutineSlot?[initialCapacity];
@ -133,7 +134,7 @@ public sealed class CoroutineScheduler(
if (_statistics != null)
{
_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;
meta.State = CoroutineState.Paused;
_pausedCount++;
return true;
}
@ -283,6 +285,7 @@ public sealed class CoroutineScheduler(
slot.State = CoroutineState.Running;
meta.State = CoroutineState.Running;
_pausedCount--;
return true;
}
@ -340,7 +343,8 @@ public sealed class CoroutineScheduler(
if (!_grouped.TryGetValue(group, out var handles))
return 0;
return handles.Count(Kill);
var copy = handles.ToArray();
return copy.Count(Kill);
}
/// <summary>
@ -409,6 +413,7 @@ public sealed class CoroutineScheduler(
_nextSlot = 0;
ActiveCoroutineCount = 0;
_pausedCount = 0;
return count;
}

View File

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