【发布时间】:2014-11-04 12:05:55
【问题描述】:
我从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 位发布版本上运行此版本并启用了优化。
【问题讨论】:
-
与问题无关,但是你写这个类是为了节省内存吗?
-
您正在犯传统的基准测试错误。就像在测量中包括抖动开销一样。并且不实际使用返回值,让抖动优化器彻底消除代码。
-
这很好。所以我在进行任何计时之前返回并添加了另一个 sub.GetHashCode() 循环。相同的结果 - 到毫秒。
-
@bright:
o-: Substring: 0.1175266; String: 0.0133497,o+: Substring: 0.0225464; String: 0.0253571;我是否先测试string或Substring方法似乎没有任何显着差异。 -
你还没有使用
sum。添加GC.KeepAlive(sum);。调试器在启动时抑制优化。在没有调试器的情况下开始。将测试持续时间延长 10 倍或更多。
标签: c# performance gethashcode