C# 字节[]的安全比较与不安全比较
我在不同的地方读过,关于使用固定块的数组之间的不安全迭代要快多少。我在.net 4和4.5中进行了尝试,或多或少都取得了相同的结果。C# 字节[]的安全比较与不安全比较,c#,pointers,bytearray,C#,Pointers,Bytearray,我在不同的地方读过,关于使用固定块的数组之间的不安全迭代要快多少。我在.net 4和4.5中进行了尝试,或多或少都取得了相同的结果。 安全比较总是更快,有时是一点点,有时几乎是一半的时间,特别是在.NET4中 我做错什么了吗 class Program { public unsafe static int UnsafeCompareTo2(byte[] self, byte[] other) { if (self.Length < other.Length)
安全比较总是更快,有时是一点点,有时几乎是一半的时间,特别是在.NET4中 我做错什么了吗
class Program
{
public unsafe static int UnsafeCompareTo2(byte[] self, byte[] other)
{
if (self.Length < other.Length) { return -1; }
if (self.Length > other.Length) { return +1; }
GCHandle selfHandle =
GCHandle.Alloc(self, GCHandleType.Pinned);
GCHandle otherHandle =
GCHandle.Alloc(other, GCHandleType.Pinned);
byte* selfPtr = (byte*)
selfHandle.AddrOfPinnedObject().ToPointer();
byte* otherPtr = (byte*)
otherHandle.AddrOfPinnedObject().ToPointer();
int length = self.Length;
int comparison = 0;
for (int index = 0; index < length; index++)
{
comparison =
(*selfPtr++).CompareTo((*otherPtr++));
if (comparison != 0) { break; }
}
selfHandle.Free();
return comparison;
}
public static int CompareTo(byte[] self, byte[] other)
{
if (self.Length < other.Length) { return -1; }
if (self.Length > other.Length) { return +1; }
int comparison = 0;
for (int i = 0; i < self.Length && i < other.Length; i++)
{
if ((comparison = self[i].CompareTo(other[i])) != 0)
{ return comparison; }
}
return comparison;
}
public unsafe static int UnsafeCompareTo(byte[] self, byte[] other)
{
if (self.Length < other.Length) { return -1; }
if (self.Length > other.Length) { return +1; }
int n = self.Length;
fixed (byte* selfPtr = self, otherPtr = other)
{
byte* ptr1 = selfPtr;
byte* ptr2 = otherPtr;
while (n-- > 0)
{
int comparison;
if ((comparison = (*ptr1++).CompareTo(*ptr2++)) != 0)
{
return comparison;
}
}
}
return 0;
}
static void Main(string[] args)
{
byte[] b1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
byte[] b2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21 };
Stopwatch watch = new Stopwatch();
watch.Start();
int result;
for(long i = 0; i < Math.Pow(10, 2); i++)
result = CompareTo(b1, b2);
watch.Stop();
Console.WriteLine("safe = {0}", watch.Elapsed);
watch.Restart();
for (long i = 0; i < Math.Pow(10, 2); i++)
result = UnsafeCompareTo(b1, b2);
watch.Stop();
Console.WriteLine("unsafe1 = {0}", watch.Elapsed);
watch.Restart();
for (long i = 0; i < Math.Pow(10, 2); i++)
result = UnsafeCompareTo2(b1, b2);
watch.Stop();
Console.WriteLine("unsafe2 = {0}", watch.Elapsed);
Console.ReadLine();
}
}
类程序
{
公共不安全静态int unsafectompareto 2(字节[]self,字节[]other)
{
if(self.Lengthother.Length){return+1;}
GCHandle自动手柄=
GCHandle.Alloc(self,GCHandleType.pinted);
GCHandle其他句柄=
GCHandle.Alloc(其他,GCHandleType.pinted);
字节*selfPtr=(字节*)
selfHandle.AddRofPindedObject().ToPointer();
字节*otherPtr=(字节*)
otherHandle.AddRofPindedObject().ToPointer();
int length=自我长度;
整数比较=0;
for(int index=0;indexother.Length){return+1;}
整数比较=0;
for(int i=0;iother.Length){return+1;}
int n=自身长度;
固定(字节*selfPtr=self,otherPtr=other)
{
字节*ptr1=selfPtr;
字节*ptr2=otherPtr;
而(n-->0)
{
整数比较;
如果((比较=(*ptr1++).比较到(*ptr2++)!=0)
{
收益比较;
}
}
}
返回0;
}
静态void Main(字符串[]参数)
{
字节[]b1={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
字节[]b2={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21};
秒表=新秒表();
watch.Start();
int结果;
for(长i=0;i
在我看来,这种差异常常被管理费用和随机噪音所淹没。我发现它更适合更多的迭代,更重要的是更长的字节数组。我制作了一个变体,它通过更频繁地避免方法调用开销而稍微快一点:
public unsafe static int UnsafeCompareTo(byte[] self, byte[] other)
{
if (self.Length < other.Length) { return -1; }
if (self.Length > other.Length) { return +1; }
int n = self.Length;
fixed (byte* selfPtr = self, otherPtr = other)
{
byte* ptr1 = selfPtr;
byte* ptr2 = otherPtr;
byte b1;
byte b2;
while (n-- > 0)
{
b1 = (*ptr1++);
b2 = (*ptr2++);
if (b1 == b2)
continue;
return b1.CompareTo(b2);
}
}
return 0;
}
它应该使用other,之后应该释放它。可能是用于比较的装箱/拆箱,我必须尝试。有趣的+1有趣的事情,去掉长度验证,在if中,第二个不安全的比较有时会赢。。。lolI尝试了更多的迭代,10^5,然后不安全是快速的耶,我认为这将是一个线性的过程,但在100000次迭代的顺序中,第一个不安全显示了执行比较的一半时间,即使它在所有时间中都是最短的,一半毫秒。。。我试过10^3次操作,保险箱速度更快,但10^5显示了大家都在谈论的性能提升。。。
GCHandle otherHandle = GCHandle.Alloc(self, GCHandleType.Pinned);