更快地替换Dictionary
我需要快速替换System.Collections.Generic.Dictionary
。 我的申请应该非常快。 所以,替换应该支持:
- generics
- 加
- 得到
- 包含
……就是这样。 我不需要LINQ或任何东西的任何支持。 它应该很快 。
一个简单的代码如:
Stopwatch stopWatch = Stopwatch.StartNew(); Dictionary dictionary = new Dictionary(); dictionary.Add("fieldName", "fieldValue"); dictionary.Add("Title", "fieldVaaaaaaaaaaaaaaaaalue"); Console.WriteLine(stopWatch.Elapsed);
…打印00:00:00.0001274,这对我来说很多时间,因为我的应用程序正在做很多其他的事情,其中一些来自旧的慢速库我必须使用并且不依赖于我。
关于如何实施更快速的任何想法?
谢谢。
你有机会看到JIT编译。 在我的盒子上,我看到:
00:00:00.0000360 00:00:00.0000060
当我在同一个过程中快速连续运行两次 – 而不是在调试器中。 (确保你没有在调试器中运行它,否则这是一个毫无意义的测试。)
现在,在任何时候测量微小通常都是一个坏主意。 您需要迭代数百万次才能更好地了解它需要多长时间。
您是否有充分的理由相信它实际上会降低您的代码速度 – 或者您是基于原始时机进行的?
我怀疑你会发现比Dictionary
更快的任何东西,我会惊讶地发现它是瓶颈。
编辑:我刚刚对Dictionary
添加一百万个元素进行基准测试Dictionary
其中所有键都是现有对象(数组中的字符串),重用相同的值(因为它不相关)并指定一个百万的容量建筑 – 我两岁的笔记本电脑花了大约0.15秒。
这真的可能是你的瓶颈,因为你已经说过你在你的应用程序的其他地方使用了一些“旧的慢速库”吗? 请记住,其他库越慢,改进的集合类的影响就越小。 如果字典更改仅占您整个应用程序时间的1%,那么即使我们可以提供即时字典,您也只能将应用程序加速1%。
与以往一样,获取一个分析器 – 它会让您更好地了解您的时间。
我同意Jon Skeet的假设,即这很可能是JIT编译。
话虽这么说,我想在这里添加一些其他信息:
与使用Dictionary
相关的大多数速度问题与Dictionary
的实现无关。 Dictionary
非常快,开箱即用。 打败它会很困难。
与Dictionary实例相关的速度问题几乎总是实际上是哈希代码实现问题。 如果您在使用Dictionary
时遇到速度问题,请重新访问您在MyCustomClass上定义的GetHashCode()
实现。 如果您使用自定义结构作为键,则这一点更为重要。
为了从Dictionary中获得良好的性能, GetHashCode()
应该是:
- 快速
- 能够提供产生很少冲突的哈希码。 在可能的情况下,唯一实例应生成唯一的哈希值。
如果你做对了,我想你会对默认的Dictionary实现非常满意。
不要忘记,您也在该代码中对Dictionary构造函数进行计时。 我做了一个测试,将测量中的调用移到构造函数中,然后循环10次。 这是我的测试代码:
for (int i = 0; i < 10; i++) { Dictionary test = new Dictionary(); System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew(); test.Add("fieldName", "fieldValue"); test.Add("Title", "fieldavlkajlkdjflkjalkjslkdjfiajwelkrjelrkjavoijl"); Console.WriteLine(watch.Elapsed); } Console.ReadKey();
以下是结果:
00:00:00.0000607 00:00:00.0000025 00:00:00.0000015 00:00:00.0000015 00:00:00.0000016 00:00:00.0000017 00:00:00.0000016 00:00:00.0000016 00:00:00.0000016 00:00:00.0000015
我不确定你得到多快多少…
更新
看起来这也反映了Jon Skeets的结果… JIT。
如果你真的需要更好的性能,那么你将不得不放弃一些重要的东西 – 比如generics,动态内存分配等等。所有这些function都会牺牲一些性能。
如果可能的话我会避免使用Contains并查看TryGetValue等。
赔率是你找不到比Dictionary更快的东西。 我会用字典。 然后,当您发现自己没有达到性能目标时,并且分析器指示从词典中添加/删除是您的瓶颈,您可以考虑使用更具针对性的类替换。
请注意,如果不使用LINQ等function,则不会导致任何性能损失。
你可以使用List并定义一个枚举,例如,fieldName = 0,Title = 1并使用每个属性的唯一索引作为列表中的查找索引吗? 这将是最快的解决方案,虽然最不灵活,因为你被绑定到枚举。
您打算将多少项添加到词典中? 虽然Dictionary / Hashtable通常是最快的,但取决于你正在做什么,可能比Hashtable(字典中的底层结构)更快(也称为更适合)。 根据用法,如果与某种跳过列表甚至是自平衡树或尝试结合使用,SortedList可能会更快。 特别是如果您希望返回一系列值而不是单个值。
Hashtable非常适合以下情况:
- 您知道在表格开始之前您打算存储多少项目。 动态resize将非常痛苦!
- 你有一个很好的哈希算法和均匀分布,.NET就是这样做的
- .NET有一个很好的机制来解决冲突
- 您正在寻找单一价值
- 您可以保证所有值都是唯一的
例如,如果您正在进行一些压缩,则RB-Tree优于Hashtable。
资料来源: http : //en.wikipedia.org/wiki/Hashtable#Dynamic_resizing
以最大性能使用密钥作为密钥:
对于那些从谷歌来到这里的人来说,如果你想从词典中挤出最后一点性能,那就用Ints作为键。 这是比较Int与String Keys的基准: https : //jacksondunstan.com/articles/2527
该文章的作者甚至提到,如果你有这样的需要,将字符串转换为int是值得的。
另请注意,在PHP等其他语言中也会出现同样的行为。 Php关联数组 – 实际上是字典,如果你在PHP7 中按升序使用Ints,它们会大大优于字符串键。