性能 - 使用Guid对象或Guid字符串作为键

63

当在 Dictionary 中使用 Guid 作为索引时,是更好地使用 Guid 对象还是其字符串表示形式?

我刚刚重构了一些代码,将字符串替换为对象,因为有很多 new Guid() 调用。但这让我想知道可能存在的性能问题。(这些集合相当小,但它们需要进行大量迭代。)

3个回答

102

Guid应该更快,因为比较更简单——只需要几个直接的字节。字符串涉及到解引用和更多的工作。

当然——你可以进行性能分析;-p

证据:

Searching for 7f9b349f-f36f-94de-ad96-04279ddf6ecf
As guid: 466; -1018643328
As string: 512; -1018643328
Searching for 870ba465-08f2-c872-cfc9-b3cc1ffa09de
As guid: 470; 1047183104
As string: 589; 1047183104
Searching for d2376f8a-b8c9-4633-ee8e-9679bb30f918
As guid: 423; 1841649088
As string: 493; 1841649088
Searching for 599889e8-d5fd-3618-4c4f-cb620e6f81bb
As guid: 488; -589561792
As string: 493; -589561792
Searching for fb64821e-c541-45f4-0fd6-1c772189dadf
As guid: 450; 1389733504
As string: 511; 1389733504
Searching for 798b9fe5-ba15-2753-357a-7637161ee48a
As guid: 415; 779298176
As string: 504; 779298176
Searching for 12ba292e-8e59-e5d0-7d04-e811a237dc21
As guid: 457; 558250944
As string: 564; 558250944
Searching for 05b3ce14-dfbf-4d3a-1503-ced515decb81
As guid: 413; 1658205056
As string: 504; 1658205056
Searching for 8db4a556-0a65-d8cb-4d0d-0104245d18b8
As guid: 415; 696231936
As string: 506; 696231936
Searching for c49cf80c-5537-fba5-eebd-8ad21bba09c4
As guid: 459; 2100976384
As string: 557; 2100976384

基于:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
static class Program
{

    static void Main()
    {
        Random rand = new Random(123456);
        int COUNT = 1000;
        Dictionary<Guid, int> guids = new Dictionary<Guid, int>(COUNT);
        Dictionary<string, int> strings = new Dictionary<string, int>(
            COUNT, StringComparer.Ordinal);

        byte[] buffer = new byte[16];
        for (int i = 0; i < COUNT; i++)
        {
            rand.NextBytes(buffer);
            Guid guid = new Guid(buffer);
            int val = rand.Next();
            guids.Add(guid, val);
            strings.Add(guid.ToString(), val);
        }

        for(int i = 0 ; i < 10 ; i++) {
            int index = rand.Next(COUNT);
            Guid guid = guids.Keys.Skip(index).First();
            Console.WriteLine("Searching for " + guid);
            int chk = 0;
            const int LOOP = 5000000;
            Stopwatch watch = Stopwatch.StartNew();
            for (int j = 0; j < LOOP; j++)
            {
                chk += guids[guid];
            }
            watch.Stop();
            Console.WriteLine("As guid: " + watch.ElapsedMilliseconds
                   + "; " + chk);
            string key = guid.ToString();
            chk = 0;
            watch = Stopwatch.StartNew();
            for (int j = 0; j < LOOP; j++)
            {
                chk += strings[key];
            }
            watch.Stop();
            Console.WriteLine("As string: " + watch.ElapsedMilliseconds
                   + "; " + chk);
        }
        Console.ReadLine();

    }
}

7
哦,你不会为我做这件事吗?;) - Benjol
2
哇,你做到了!答案是你的,先生! - Benjol
实际上,这些数字涵盖查找时间。添加操作没有被分析。 - Marc Gravell
1
@FlyOn:嗯,是的。已经快4年了... :-) - Richard
1
字符串不是更快,而是更慢。 - Triynko

2

这些集合相当小,但它们被迭代了很多次

如果您正在进行迭代,则没有键对键的比较。如果您正在按键添加/修改或查找,则会对键进行哈希并比较哈希;仅当哈希相等时,才会比较键。

因此,除非在具有许多哈希冲突的大型字典上执行许多基于键的操作,否则键到键的比较速度不会成为主要因素。


是的,我表达得不好。如果没有查询,拥有字典也没有多大意义! - Benjol
一个字典确保键是唯一的,并且具有O(log n)的插入时间;即使您只需要迭代,这也非常有用。 - Richard
(请查看我在帖子上的评论的回复) - Marc Gravell
如果您不需要键/值语义,但想确保唯一性,则使用 HashSet 可能是更好的选择。 - jocull

1

我的第一反应可能是,Guid对象更快,但如果您以字符串形式获取一些输入,并且必须在小的GUID集合(哈希集)中搜索它们(这些GUID不经常更改),则将它们存储为字符串可能更快,因为:

  • 要在GUID字典中搜索字符串,您必须解析字符串(包括错误检查等),创建Guid结构,获取哈希码,进行哈希查找并进行GUID字节的最终比较。

  • 要在字符串字典中搜索字符串,您必须构建字符串的哈希(可能比构建Guid结构更快),查找哈希并进行一次字符串比较。例如,如果您预计许多GUID不在集合中,则哈希比较将经常失败,您甚至不必执行字符串比较(比起上面第1点的GUID比较需要稍微更长的时间)

如果您已经有了Guid结构作为输入(例如,因为您对输入字符串进行了某些有效性检查),那么当然最好重用它们作为字典中的索引。

但是:从设计清晰度的角度来看(这比代码性能在99%的情况下更重要),您应该使用Guid结构,并仅在真正遇到性能问题(并且分析显示字符串解决方案可以带来优势)时才更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接