Dictionary <string,object =“”> vs List <string> + BinarySearch的性能

时间:2016-06-05 00:06:29

标签: c# .net performance

我有一个自定义性能计时器实现。简而言之,它是存储某些代码路径的执行持续时间的静态数据集合。为了识别特定的测量,我需要一组命名对象,可以通过名称快速访问数据项,即中等长度的string,如20-50个字符。

直截了当的方法可以是Dictionary<string, MyPerformanceCounter>,可以通过密钥访问,这是计数器ID。

通过List<MyPerformanceCounter>List<T>.BinarySearch排序可以访问和维护的List.Insert怎么办?当我需要数百个计数器时,它是否有机会获得更多线性性能?

毋庸置疑,我需要尽可能快地访问正确的MyPerformanceCounter,因为它以每秒几十万的速率调用,并且应该尽可能少地影响代码执行。

新计数器相对较少,每秒一次。

2 个答案:

答案 0 :(得分:2)

字典中有几个可能非O(1)的部分。

第一个是生成哈希码。如果您的字符串很长,则每次将其用作字典中的键时,都必须生成字符串的哈希值。字典存储现有密钥的哈希值,因此您不必担心这一点,只需散列您传入的内容。如果字符串都很短,则散列应该很快。与字符串比较相比,长字符串可能需要更长的时间来进行哈希处理。散列会影响读写。

字典的下一个非常量部分是当你有哈希冲突时。它在内部保留了一个具有相同哈希桶的值的链接列表,如果发生哈希冲突,它必须通过并将您的密钥与该桶中的每个项目进行比较。由于你正在使用字符串,并且他们花了很多精力来提供良好的字符串散列函数,这不应该是一个太大的问题。散列冲突会减慢读写速度。

最后一个非常量部分仅在写入期间,如果它耗尽内部存储,则必须在内部重新计算整个哈希表。这仍然比进行数组插入要快得多(就像List&lt;&gt;那样)。如果你只有几百件商品,那绝对不会影响你。

另一方面,列表每个插入平均需要N / 2个副本,每个查找需要log2(N)。除非字符串都有相似的前缀,否则单个比较将比字典快得多,但会有更多的字典。

因此,除非你的字符串很长,以使散列效率低下,否则字典很可能会给你提供更好的性能。

如果您对字符串的性质有所了解,可以编写针对您的方案优化的更具体的数据结构。例如,如果我知道所有字符串都以ASCII大写字母开头,并且每个字符串的长度在5到10个字符之间,那么我可能会创建一个包含26个数组的数组,每个字母对应一个数组,然后每个数组包含6个列表,每个字符串长度一个。像这样:

List<string>[][] lists = new List<string>[26][6];
foreach (string s in keys)
{
    var list = lists[s[0] - 'A'][s.Length - 5];
    if (list == null)
    {
        lists[s[0] - 'A'][s.Length] = list = new List<string>();
    }
    int ix = list.BinarySearch(s);
    if (ix < 0)
    {
        list.Insert(~ix, s);
    }
}

如果您有关于您正在处理的数据类型的非常具体的信息,那么这就是您要做的事情。如果你不能做出假设,使用词典很可能是你最好的选择。

如果你想要二进制搜索路由,你可能还想考虑使用OrderedDictionary,我相信它在内部使用二进制搜索树。 https://msdn.microsoft.com/en-us/library/system.collections.specialized.ordereddictionary%28v=vs.110%29.aspx

答案 1 :(得分:0)

我相信你应该使用/path/default/path_1

对于小型数据集,列表将具有更好的性能。然而,由于需要更多的元素,词典变得明显优越。

  • Dictionary<string, MyPerformanceCounter>所需的时间为: O(1) 常量时间 复杂。
  • 列表的 O(N) 线性时间复杂度。

您可以尝试DictionaryHashtable,但我认为您仍应使用SortedDictionary

我在此处提供了基准和指南的链接:http://www.dotnetperls.com/dictionary-time

我希望这会对你有所帮助。