【问题标题】:Key performance for a dictionary字典的关键性能
【发布时间】:2011-08-10 06:02:05
【问题描述】:

string 键比Dictionary<,> 中的int 键快吗?

【问题讨论】:

  • 您如何确定关键性能在您的应用程序中很重要?不要进行过早的优化。
  • 首先,决定在字典中存储什么。然后,很久以后,如果你确定你有性能问题,测量你的程序性能,找出最优化的候选者,然后从那里开始。您当前的问题不太可能产生太大影响,除非您“以性能的名义”到处使用错误的数据类型。
  • 如果您的 int 键空间有限,您有时可以使用 T[] 并使用索引器作为键,这会占用更多内存但比使用字典快很多。
  • 从未将其视为问题。如果设计说我需要映射 string => xx 那么这就是我所做的。我确信添加魔法来执行字符串 -> 魔法 -> int => x 会更慢(如果没有,那么 .net 字典团队已经完成了)

标签: .net performance dictionary


【解决方案1】:

没有。首先,Dictionary [更新] 使用密钥的哈希码在其内部存储中找到它们 - 而不是密钥。 哈希码是int。对于int,它只是int 的值,对于string,它必须生成。

所以使用int稍微快一点。


事实上,为字符串生成哈希码是一个相当复杂的过程(使用反射器的 sn-p)[希望这不会被视为侵犯版权,因为它不是]:

fixed (char* str = ((char*) this))
{
    char* chPtr = str;
    int num = 0x15051505;
    int num2 = num;
    int* numPtr = (int*) chPtr;
    for (int i = this.Length; i > 0; i -= 4)
    {
        num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
        if (i <= 2)
        {
            break;
        }
        num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
        numPtr += 2;
    }
    return (num + (num2 * 0x5d588b65));
}

【讨论】:

  • 字典也存储键,但它使用哈希码来确定存储它们的位置。答案有点不准确。
  • 是的。傻我...我会更新它。我的意思是为了检索值。
  • 但我同意你的观点,int 稍微快,因为没有计算要执行,例如 string.GetHashCode() 方法必须执行的计算.
  • 实际上@megabobik 的答案显示慢了 5-10 倍(但谁在乎)
【解决方案2】:

我知道这是一个相当古老且已回答的问题,所以这个答案适用于将来寻找它的每个人。对我来说,这也是一个有趣的问题,我试图找到这个问题的实际答案,结果非常有趣。

通常 String 作为 key 比 int 作为 key 慢很多。

代码:

class Program
{
    object obj = new object();

    Dictionary<long, object> longDict = new Dictionary<long, object>();
    Dictionary<string, object> stringDict = new Dictionary<string, object>();

    public static void Main(string[] args)
    {
        Program hash = new Program();

        hash.Test(1000);
        hash.Test(10000);
        hash.Test(100000);
        hash.Test(1000000);
        hash.Test(10000000);

        Console.Read();
    }

    private void Test(int iterations)
    {
        Console.WriteLine(String.Format("Test for {0} iterations", iterations));

        longDict.Clear();
        stringDict.Clear();

        for (int i = 0; i < iterations; i++)
        {
            longDict.Add(i, obj);
        }

        for (int i = 0; i < iterations; i++)
        {
            stringDict.Add(i.ToString(), obj);
        }

        IntTest(iterations);
        StringTest(iterations);
    }

    private void IntTest(int iteraions)
    {
        System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
        stopwatch.Start();

        object test;

        for (int i = 0; i < iteraions; i++) {
            test = longDict[i];
        }

        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
    }

    private void StringTest(int iteraions)
    {
        System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
        stopwatch.Start();

        object test;

        for (int i = 0; i < iteraions; i++)
        {
            test = stringDict[i.ToString()];
        }

        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
    }
}

结果:

【讨论】:

  • 您应该以某种方式从 Dictionary 的结果中排除不相关的“i.ToString()”操作的时间。
  • 警告:这些结果具有误导性,因此比无用更糟糕。问题:1:i.ToString() 花费了时间。 2:弦很短。 3:字典大小不同(缓存命中/未命中)。 (制作大型字典并重复使用它们。) 4:检索到的元素不得立即丢弃(编译器优化)。 5:还应该测试int 的键,而不仅仅是long。 6:由于 JIT,第一批运行应该被忽略。 7:需要三个参数:(nIterations, nElements, stringLength)
  • 我删除了 i.ToString() 并缓存了这里的值:gist.github.com/juanpaexpedite/757e3b15dbdf5cb52453c7fe42effacf。我测试并存储 in 哈希比存储字符串键更好,除非我做的事情不是性能。
  • 您应该使用 BenchmarkDotNet 进行正确的性能测试。
【解决方案3】:

我和 magabobik 在一起。只是为了消除i.ToString() 的影响。我在他的代码中更改了以下内容。但仍然 Int 更快。

longDict.Add(i, obj); 替换为longDict.Add(int.Parse(i.ToString()), obj);

结果

Test for 1000 iterations
Time elapsed: 00:00:00.0000164
Time elapsed: 00:00:00.0002208
Test for 10000 iterations
Time elapsed: 00:00:00.0001618
Time elapsed: 00:00:00.0022131
Test for 100000 iterations
Time elapsed: 00:00:00.0016835
Time elapsed: 00:00:00.0429761
Test for 1000000 iterations
Time elapsed: 00:00:00.0318415
Time elapsed: 00:00:00.3557074

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-26
    • 2014-05-23
    • 2022-01-25
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    • 2018-02-03
    相关资源
    最近更新 更多