2013-05-09 24 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); 

應該使用其他,並且應該釋放後它。