.NET 6中SortedSet添加已确认唯一的元素时随机失败的问题排查求助
.NET 6中SortedSet添加已确认唯一的元素时随机失败的问题排查求助
各位大佬好,我最近在维护一个.NET 6应用时,碰到了SortedSet<T>的一个诡异问题——明明要添加的元素都是唯一的,但有时候就是会有元素加不进去,触发我的警告日志。折腾了好几天都没找到根源,想请大家帮忙分析下。
问题场景与核心代码
我封装了一个批量添加元素到SortedSet的方法,代码如下(锁对象是全局唯一的,所有访问这个SortedSet的方法都会用它加锁):
private readonly SortedSet<T> sortedSet = new(); private readonly object lockObj = new(); public void AddRange(IEnumerable<T> items) { lock (lockObj) { var count = items.Count(); var added = 0; foreach (var item in items) { if (sortedSet.Add(item)) added++; } if (added != count) { logger.Warning("预期添加{Count}个元素,实际仅添加{Added}个", count, added); } } }
这段代码会随机触发警告:实际添加的元素数量比传入的总数少1个,但我完全找不到原因。
已完成的排查步骤
验证待添加元素的唯一性:我在锁内部加了一段调试代码,用
HashSet<T>确认传入的items没有重复:var debugSet = new HashSet<T>(); debugSet.UnionWith(items); logger.Information("传入{count}个元素,其中{unique}个是唯一的", items.Count(), debugSet.Count);日志显示每次传入的元素数量和
HashSet的计数完全一致,说明所有待添加元素都是唯一的。确认并发访问安全:我逐一检查了所有操作这个
SortedSet的方法——不管是添加、删除还是查询,全部都用了同一个lockObj加锁,按道理不会出现并发修改的问题。元素类型的细节:这里的
T是一个记录类型ScheduledAutoload,定义如下:public record ScheduledAutoload : IScheduled, IComparable<IScheduled> { public ScheduledAutoload(Guid id, DateTime scheduledTime) { Id = id; ScheduledTime = scheduledTime; } public Guid Id { get; init; } // 每个实例都有唯一的Id public DateTime ScheduledTime { get; init; } // 其他几个init-only属性 public int CompareTo(IScheduled obj) { return ScheduledTime.CompareTo(obj.ScheduledTime); } }这是个record类型,默认的相等性判断基于所有属性,而且我也通过
HashSet验证了实例是唯一的。不过我自定义了CompareTo方法,让SortedSet按ScheduledTime排序。
我的核心疑问
现在我实在搞不懂:
- 锁已经确保了
SortedSet的访问是单线程的,为什么还会出现元素加不进去的情况? - 明明
HashSet都确认元素是唯一的,为什么SortedSet.Add()会返回false? - 会不会是自定义的
CompareTo方法导致SortedSet的相等判断逻辑和HashSet不一致?
我知道用SortedSet.UnionWith()可能会更高效,但我现在想先搞清楚这个问题的根源,再做代码优化。有没有大佬遇到过类似的情况,或者能帮我分析下可能的原因?
内容来源于stack exchange
相关产品推荐
相关产品推荐

