HashSet中ValueType.Equals性能低下问题及优化方案问询
问题分析与解决方案
性能瓶颈原因
你遇到的问题根源在于HashSet<object>默认使用的ObjectEqualityComparer:
- 对于值类型,它会调用
ValueType.Equals做逐字段的值比较,这是非常耗时的操作; - 对于字符串(虽为引用类型),它会执行值相等判断而非引用相等判断;
- 仅当对象是未重写
Equals的引用类型时,才会用引用相等判断,但你的场景里存在大量触发值比较的类型,导致95%的时间消耗在Equals调用链上。
而你实际需要的是基于对象实例引用的相等判断——只检查是否为同一内存地址的实例,这才是真正O(1)时间复杂度的操作。
高效解决方案:自定义引用相等比较器
不需要为所有类重写Equals和GetHashCode,只需要实现一个基于引用相等的IEqualityComparer<object>,让HashSet用它来做判断:
using System.Runtime.CompilerServices; public class ReferenceEqualityComparer : IEqualityComparer<object> { public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer(); private ReferenceEqualityComparer() { } public bool Equals(object x, object y) { return object.ReferenceEquals(x, y); } public int GetHashCode(object obj) { // 获取对象的引用哈希码(基于内存地址,稳定且高效) return RuntimeHelpers.GetHashCode(obj); } }
修改原代码的使用方式
创建visited集合时传入这个自定义比较器:
// 初始化visited集合 var visited = new HashSet<object>(ReferenceEqualityComparer.Instance); // 调用RunFD方法 RunFD(fileObj, visited);
效果说明
- 这个比较器会直接用
object.ReferenceEquals判断两个对象是否为同一实例,完全跳过值类型的逐字段比较; RuntimeHelpers.GetHashCode返回的是对象的引用哈希码,计算速度极快,且同一实例的哈希码始终一致;- 对于值类型,装箱后的每个实例都是不同的引用,会被视为不同对象,但你的场景中循环引用仅存在于引用类型实例,因此不会影响原有功能;如果确实需要值类型的去重,可以单独处理这类场景,但根据你的描述,这不是必要的。
内容的提问来源于stack exchange,提问作者user23787413
相关产品推荐
相关产品推荐

