【问题标题】:How expensive is a GUID cast and comparison vs a string comparisonGUID 转换和比较与字符串比较的成本是多少
【发布时间】:2010-01-22 20:15:42
【问题描述】:

哪个更快?

bool same=(Guid)Identifier==id;

bool same=String.Equals(string1,string2, StringComparison.OrdinalIgnoreCase);

【问题讨论】:

  • 类似(但不相同)的问题stackoverflow.com/questions/713109/…
  • 什么时候,这很重要?这听起来像是一个微优化的案例,应该不惜一切代价避免。请记住,首先让它工作,然后(如果需要)让它更快。

标签: c#


【解决方案1】:

我使用了这个代码:

object victim = Guid.Empty;
Guid target = Guid.NewGuid();

Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000000; i++){
    bool equal = ((Guid) victim) == target;
}
Console.WriteLine("Direct cast   : {0}", sw.Elapsed);

sw.Reset(); sw.Start();
for (int i = 0; i < 10000000; i++)
{
    bool equal = Guid.Equals(victim, target);
}
Console.WriteLine("Guid.Equals   : {0}", sw.Elapsed);

sw.Reset(); sw.Start();
string a = victim.ToString(); // as suggested by Mikael
string b = target.ToString();
for (int i = 0; i < 10000000; i++)
{
    bool equal = String.Equals(a, b, StringComparison.OrdinalIgnoreCase);
}
Console.WriteLine("String.Equals : {0}", sw.Elapsed);

Console.ReadLine();

并得到不同值的结果(最佳方案):

object victim = Guid.Empty;
Guid target   = Guid.NewGuid();
// Direct cast   : 00:00:00.1164198
// Guid.Equals   : 00:00:02.1268147
// String.Equals : 00:00:00.4129527  // oh my!

这个结果是相同的值(更糟糕的情况)

object victim = Guid.Empty;
Guid target   = Guid.Empty;
// Direct cast   : 00:00:00.2793173
// Guid.Equals   : 00:00:03.5625948
// String.Equals : 00:00:01.7564302

【讨论】:

  • 您的基准测试在字节 1 上退出比较,这是最好的努力。如果您比较更多字节,则时间会相差更多。但是时间差异并不像您声称的那么大,因为您已将 .ToString() 包含在循环中。字符串 a = 受害者.ToString();字符串 b = target.ToString(); for (int i = 0; i
  • @Mikael,不错的提示;您的建议大大提高了 string.equals 的性能。
【解决方案2】:

在我进行直接 UUID-UUID 比较 VS String-String 比较的测试中,UUID 比较所用的时间大约是 String 比较的 1/4。

然而,String->UUID 的转换是昂贵的。比 UUID->String 转换要贵得多。两者都比任何一种比较方法都贵。

所以: 如果您有两个 UUID,请直接比较 UUID。 如果你有两个字符串直接比较字符串。 如果您有一个字符串和一个 UUID,请将 UUID 转换为字符串并比较字符串。

【讨论】:

    【解决方案3】:

    Guid == Guid 将使用如下代码:

    public bool Equals(Guid g)
    {
    if (g._a != this._a)
    {
        return false;
    }
    if (g._b != this._b)
    {
        return false;
    }
    

    而您示例中的字符串比较将使用不安全的指针比较。

    如果不对其进行基准测试,我怀疑 Guid 会更快,但我们谈论的是边缘化。而且您确实需要将比较次数增加到数百万次才有意义。

    两种比较都会提前爆发,即从左到右,因此也会影响速度。字符串比较在比较发生之前进行了更多检查,并且还进行了一次方法调用。

    【讨论】:

    • 他说更快,而不是更安全,尽管我很想知道不区分大小写的字符串比较如何使用指针比较。
    • “unsafe”关键字不一定不安全,但它允许您像在 C++ 中一样使用内存指针。 .Net 框架中的许多功能都是以这种方式实现的。所以这两种方法使用起来同样安全:) 我只是指框架中的实际函数 - private static unsafe int CompareOrdinalIgnoreCaseHelper(string strA, string strB)
    • @Adam Robinson 查看带有反射器的 private static unsafe int CompareOrdinalIgnoreCaseHelper(string strA, string strB),它们使用 char 指针和整数。
    【解决方案4】:

    GUID 比较是 16 字节的 memcmp。它不会比字符串比较更糟糕,但是如果您非常关心性能,则不应该使用托管代码。

    【讨论】:

    • 他的字符串比较不区分大小写。虽然比较在时间上应该没有太大差异,但它不像 Guid 那样逐字节比较。
    • 不是。 .Net guid 由 Int32+Int16+Int16+(bytes*8) 组成。并将一个与另一个进行比较,直到最后一个字节。意味着最多 11 次比较。
    • 托管代码实际上非常快 - 比我上次检查的 C++ 慢约 25-50%,与 Java 大致相同...相比之下,Python/Ruby 慢 8,000%,慢 50,000%对于 PHP...
    • @BlueRaja:不可能更快,托管代码是它自己的世界,为了接触任何东西真实的东西 - 文件、互联网等,你必须离开托管代码。如果您需要绝对的最佳性能,最好一开始就留在应用程序域之外。
    • @Mikael:真的会进行 11 次比较吗?这在非托管代码中的 4 次比较中完成,并且如果 memcmp 是内在函数,则无需函数调用的开销。
    【解决方案5】:

    .NET Guid 是一个 16 字节的结构,当它表示为一个字符串时,它将被格式化为大约 32 个字符的“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”模式。

    因此表示为一个 GUID,它将占用 16 个字节,并且 表示为一个字符串,它将占用 32*2 = 64 个字节。

    所以 GUID.Equals() 应该表现更好。

    此外,GUID.Equals(GUID) 的性能会比 guid1 == guid2 更好,因为前者不涉及装箱。

    【讨论】:

    • Guid.Equals(object, object) 所以你将参与取消/装箱;请看我的基准测试
    • Guid.Equals(Guid) 在这里描述。 msdn.microsoft.com/en-us/library/asw89aw8.aspx。看起来这个重载没有涉及拳击。
    • 哦,对不起,我以为你说的是​​静态版本;但是,无论如何,您需要使用 Guid.Equals(object) ,因为整点是关于从对象进行转换
    • 我的快速测试表明 Guid.Equals(object, object) 非常慢。事实上,它比 guid1 == guid2 慢了大约 5 倍。我发现最快的是 guid1.Equals(guid2)。这比旧计划快 20% ==
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 2021-08-05
    • 2011-08-02
    • 2014-09-17
    相关资源
    最近更新 更多