是什么原因导致GetHashCode的实现比.net的实现慢20倍?

时间:2014-09-10 18:09:12

标签: c# performance gethashcode

我从this帖子和this帖子中了解了一个子串struct。第二篇文章实现了.net的String.GetHashCode()。 (我不确定.net的版本是哪个。)

这是实施。 (GetHashCode取自上面列出的第二个来源。)

public struct Substring
{
    private string String;
    private int Offset;
    public int Length { get; private set; }
    public char this[int index] { get { return String[Offset + index]; } }

    public Substring(string str, int offset, int len) : this()
    {
        String = str;
        Offset = offset;
        Length = len;
    }

    /// <summary>
    /// See http://www.dotnetperls.com/gethashcode
    /// </summary>
    /// <returns></returns>
    public unsafe override int GetHashCode()
    {
        fixed (char* str = String + Offset)
        {
            char* chPtr = str;
            int num = 352654597;
            int num2 = num;
            int* numPtr = (int*)chPtr;
            for (int i = Length; i > 0; i -= 4)
            {
                num = (((num << 5) + num) + (num >> 27)) ^ numPtr[0];
                if (i <= 2)
                {
                    break;
                }
                num2 = (((num2 << 5) + num2) + (num2 >> 27)) ^ numPtr[1];
                numPtr += 2;
            }
            return (num + (num2 * 1566083941));
        }
    }
}

这是一个单元测试:

    [Test]
    public void GetHashCode_IsAsFastAsString()
    {
        var s = "The quick brown fox";
        var sub = new Substring(s, 1, 5);
        var t = "quick";
        var sum = 0;

        sum += sub.GetHashCode(); // make sure GetHashCode is jitted 

        var count = 100000000;
        var sw = Stopwatch.StartNew();
        for (var i = 0; i < count; ++i)
            sum += t.GetHashCode();
        var t1 = sw.Elapsed;
        sw = Stopwatch.StartNew();
        for (var i = 0; i < count; ++i)
            sum += sub.GetHashCode();
        var t2 = sw.Elapsed;

        Debug.WriteLine(sum.ToString()); // make sure we use the return value
        var m1 = t1.Milliseconds;
        var m2 = t2.Milliseconds;
        Assert.IsTrue(m2 <= m1); // fat chance
    }

问题是m1是10毫秒,m2是190毫秒。 (注意:这是1000000次迭代。) 仅供参考,我在启用了优化功能的.net 4.5 64位发布版本上运行此功能。

1 个答案:

答案 0 :(得分:-1)

  1. 评论说,我仔细检查以确保优化代码正在运行。事实证明,obscure Debugger setting禁用了优化。所以我取消选中工具 - 选项 - 调试 - 常规 - 抑制模块加载时的JIT优化(仅限管理)。这导致优化的代码正确加载。
  2. 即使开启优化,仍然会有大约3倍到6倍的差异。但是,这可能是因为上面的代码是.net 32​​位版本而我正在运行64位.net。将string.GetHashCode的64位实现移植到Substring并不容易,因为它依赖于字符串标记的零端(实际上是bug)。
  3. 此时我对没有获得平价表现感到失望,但这充分利用了我的时间来了解优化C#的一些危险和陷阱。