- A+
利用哈希的其中一个思想,相同的对象的哈希值相同,可以用来提升一些大对象集合的进行对象相等判断的性能。大对象的相等判断指的是有某些类型的相等判断需要用到对象的很多属性或字段进行参与判断逻辑才能判断两个对象是否相等,当这些大对象存放在集合里面,此时进行大量的相等判断将会因为需要有大量的属性或字段的判断而降低性能。本文告诉大家如何使用此哈希的思想提升判断的性能
故事的背景是我在做一个比 Office 的 Word 差得多的软件,此软件有文本的功能,允许每个文字都有自己的文本属性。有趣的是,我期望将文本的文本属性进行合并,总不能一篇一万字的博客有一万个文本属性吧。但文本属性是一个比较大的类型,里面包含了一堆属性,如字体字号等等
在拿到输入的一堆文本属性的集合里面,需要进行文本属性对象之间的相等判断用于合并多余的文本属性。在使用 dotTrace 进行性能测量时,了解到有大量的资源都用在了相等判断里面,因为一个文本属性和另一个文本属性的相等比较大约需要比较近 100 个属性。不要听着 100 个属性很惊讶,在 Word 里面可是按照 MB 计算的属性量哦
在进行性能优化的时候,我考虑用上哈希的思想。思想就是将大对象的相等比较分为两步,第一步判断大对象的哈希值是否相等。基于相等的对象的哈希值相等的思想,可以了解到想要两个对象相等,第一步判断哈希值必须相等。在判断哈希之后再进行大对象原本的对象相等判断
判断哈希值相当于只是判断一个 int 值而已,占用资源基本可以被忽略。因此可以在存在比较多不相同的对象的时候,可以提升对不相同对象的判断的性能从而提升集合的判断相等的性能
以下是更详细的细节
在制作对象的哈希值的时候,期望是将所有参与相等判断的属性和字段都加入到哈希值的创建中,这样创建出来的哈希值将会包含所有参与判断的字段和属性的信息。但同时也会带来一个问题是哈希值的计算也是需要计算资源的,可以考虑将哈希值进行缓存
在 dotnet 里面,默认对象的 GetHashCode 是不推荐将非只读的属性和字段加入到此方法的哈希值制作。但是在本文的需求下,是无视此条例,需要将所有参与判断相等的属性和字段都加入哈希值的制作。因此建议本文的方法不要放入到对象的 GetHashCode 方法里面,而是自己再创建一个新方法或者放在某个辅助类
在制作大对象的哈希值时,需要充分考虑业务上的需要,宁可哈希冲突大一些也不要误判。也就是说宁可两个不相等的对象返回相同的哈希值,也不要有存在某些相等的对象可能返回不同的哈希值。其细节在于,在大对象里面,引用的一些属性对应的类型所获取的哈希值如果不能准确获取,如是一个接口等,那么建议将此属性或字段不加入到哈希值的制作。相当于判断哈希值是例外了此属性或字段的判断。其原因是接口相对来说是自由的,如果有某些业务诡异实现了此接口,让原本两个相等的对象返回了不相等的哈希值,那么将会让本文的逻辑炸掉