2013-05-09 49 views
4

我读过在不同的地方,如何更快的是使用固定块阵列之间的不安全迭代。我试过.net 4和4.5,或多或少的达到了相同的结果。
安全比较总是比较快,有时候会比较快,有时差不多有一半时间,特别是在.net 4中。安全比较VS不安全,对于字节[]

我做错了什么?

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(); 
    } 
} 
+1

可能是拳击/拆箱的比较,我得试试。有趣的+1 – 2013-05-09 03:04:55

+0

有趣的事情,拿出lenght验证,在如果的,有时第二不安全比较成功...笑 – 2013-05-09 03:09:23

+0

我试图与更多的iteractions,10^5,然后不安全也较快 – 2013-05-09 03:12:04

回答

1

它看起来像差异往往被开销和随机噪声淹没。我发现它更多地反映了更多的迭代,更重要的是更长的字节数组。我做了一个变体,它是一个快一点通过避免方法调用的开销更频繁:

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; 
} 

我也注意到一个bug在你的代码(没有慢下来真的),在下面的一行:

GCHandle otherHandle = GCHandle.Alloc(self, GCHandleType.Pinned); 

应该使用其他,并且应该释放后它。