我应该关注.NET字典的速度吗?

时间:2009-12-14 20:18:00

标签: c# arrays optimization dictionary

我将创建一个将使用字典查找和插入相当多的项目。这是值得关注的吗?

另外,如果我进行基准测试并且确实很糟糕,那么用其他东西替换字典的最佳方法是什么?使用带有“散列”键的数组会更快吗?那会对插入时间有所帮助吗?

另外,我不认为我是微优化的,因为这确实是生产服务器上代码的重要组成部分,所以如果这需要额外的100ms来完成,那么我们将寻找新的方法来处理这个(事情。

12 个答案:

答案 0 :(得分:78)

  1. 微优化。你甚至还有工作代码吗?请记住,“如果它不起作用,那么快速如何不起作用并不重要。” (Mich Ravera)http://www.codingninja.co.uk/best-programmers-quotes/

    您不知道瓶颈会在哪里,而且您已经专注于词典。如果问题出在其他地方怎么办?

  2. 您如何知道Dictionary类的实现方式?也许它已经使用了带有散列键的数组!
  3. P.S。它实际上是“.NET Dictionaries”,而不是“C#Dictionaries”,因为C#只是使用框架的几种编程语言之一。

答案 1 :(得分:65)

  

您好,我将创建一个项目   这将使用字典查找和   插入相当多。这是什么东西   要关注?

是。预先考虑性能因素总是明智的。

您应关注的形式如下:您的关注应该是鼓励您编写切合实际的,以用户为中心的性能规范。应该鼓励您尽早开始编写性能测试并经常运行它们,这样您就可以看到产品的每一次更改都会影响性能。这样,当代码更改导致影响用户的性能变化时,您将立即得到通知。它应该鼓励你经常运行配置文件,这样你就可以根据经验测量来推断性能,而不是随机猜测和预测。

  

另外,如果我做基准测试等   它真的很糟糕,然后是什么   用词替换词典的最佳方法   别的什么?

执行此操作的最佳方法是构建合理的抽象层。如果您有一个表示“插入”和“查找”抽象数据类型的类(或接口),则可以在不更改任何调用者的情况下替换其内部。

请注意,添加一个抽象层本身会带来性能成本。如果您的分析显示抽象层太昂贵,如果每次调用额外的几纳秒太多,那么您可能不得不摆脱抽象层。同样,这个决定将由现实世界的性能数据驱动。

  

使用带有“哈希”的数组   键甚至更快?那不会   有关插入时间的帮助吗?

你或任何阅读此内容的人都不可能知道哪一个更快,直到你以两种方式编写它,然后在真实条件下对它进行基准测试。在“实验室”条件下进行此操作会使您的结果产生偏差;当GC处于实际内存压力下时,您需要了解其工作原理,等等。你不妨问我们明年肯塔基德比赛中哪匹马会跑得更快。如果我们只是通过观察比赛形式就知道答案,我们都已经变得富有了。在未指定的条件下,你不可能指望任何人知道两个完全假设的,不成文的代码中的哪一个会更快!

答案 2 :(得分:10)

Dictionary<TKey, TValue>类实际上是作为哈希表实现的,它使查找速度非常快(接近O(1))。有关详细信息,请参阅the API documentation。我怀疑你自己能做出更好的实施。

答案 3 :(得分:10)

等一下,看看您的应用程序的性能是否低于预期 如果是,则使用分析器确定字典查找是否是问题的根源 如果是,那么使用代表性数据进行一些测试,看看是否有更快的选择列表。

简而言之 - ,一般情况下,在遇到问题之前,您不应该担心实施细节的效果。

答案 4 :(得分:5)

我会做一下Dictionary,HashTable(.NET中的HashSet),也许是一个本土的类的基准测试,看看哪种方法在你的典型使用条件下效果最好。

通常我会说没关系(在这里插入StackOverflow最喜欢的早泄名称),但如果这是应用程序的核心,Benchmark,Benchmark,Benchmark。

答案 5 :(得分:4)

我能想到的唯一问题是字典的速度依赖于具有相当快的GetHashCode方法的密钥类。查找和插入非常快,所以你不应该有任何问题。

关于使用数组,这就是Dictionary类已经做的事情。实际上它使用两个数组,一个用于键,一个用于值。

如果你对Dictionary有任何性能问题,那么为任何类型的存储创建一个包装器会非常容易,它具有与Dictionary相同的方法和行为,因此你可以无缝地替换它。

答案 6 :(得分:4)

我不确定是否有人真的回答过这一部分:

  

另外,如果我做基准测试等   它真的很糟糕,然后是什么   用词替换词典的最佳方法   别的什么?

为此,尽可能将变量声明为IDictionary<TKey, TValue>。这是Dictionary派生的主要界面。 (我假设如果你非常关心性能,那么你不会考虑非泛型集合。)然后,在将来,您可以更改底层实现类,而无需更改任何使用该代码的代码。字典。例如:

IDictionary<string, int> myDict = new Dictionary<string, int>();

答案 7 :(得分:2)

如果你的应用程序是多线程的,那么性能的关键部分就是正确地同步这个字典。

如果它是单线程的,那么几乎可以肯定的瓶颈将在其他地方。比如从你阅读它们的任何地方读取这些物体。

答案 8 :(得分:1)

查看C# HybridDictionary Usage

HybridDictionary Class

  

建议将此类用于案例   其中元素的数量   字典未知。它需要   提高性能的优势   一个ListDictionary的小   收藏品,并提供   切换到的灵活性   Hashtable处理更大   集合优于ListDictionary

答案 9 :(得分:1)

我使用Dictionary for UDP中继服务器。每次数据包到达时,它执行Dictionary.ContainsKey和Dictionary [Key],它工作得很好(大量的客户端)。我在做这件事时有些担心,但事实证明这是我应该担心的最后一件事。

答案 10 :(得分:0)

您可以考虑使用C5库。我发现它非常快速且经过精心设计。 stackoverflow上的其他人也发现了相同的情况。使用C5,您可以选择使用通用类型接口(使用captial I),或直接使用下面的数据结构。当然,接口允许您交换不同的实现,但我在性能测试中发现接口将花费您。

答案 11 :(得分:-3)

您可能希望查看System.ObjectModel中的KeyedCollection类。从MSDN描述中,“为其键嵌入值的集合提供抽象基类。”