没有绑定检查的C#byte []比较

时间:2010-01-31 21:26:29

标签: c# performance arrays comparison byte

我正在寻找性能有效的方法来比较两个字节[]的相等性。大小超过1 MB,因此应尽量减少每个数组元素的开销。

我的目标是为两个数组提高SequenceEqualhand-coded for-loop over every item的速度avoiding the repetitive bound checks。与Array.Copy导致快memcpy的方式相同,会导致memcmp

4 个答案:

答案 0 :(得分:16)

您可以使用不安全的代码来执行指针操作。您可以将四个字节一次比较为整数:

public static bool ArrayCompare(byte[] a, byte[] b) {
  if (a.Length != b.Length) return false;
  int len = a.Length;
  unsafe {
    fixed(byte* ap = a, bp = b) {
      int* aip = (int*)ap, bip = (int*)bp;
      for (;len >= 4;len-=4) {
        if (*aip != *bip) return false;
        aip++;
        bip++;
      }
      byte* ap2 = (byte*)aip, bp2 = (byte*)bip;
      for (;len>0;len--) {
        if (*ap2 != *bp2) return false;
        ap2++;
        bp2++;
      }
    }
  }
  return true;
}

A对一个简单的循环进行了测试,它的速度提高了大约六倍。

正如Josh Einstein所建议的那样,长期可用于64位系统。实际上它在32位和64位系统上似乎几乎快了两倍:

public static bool ArrayCompare64(byte[] a, byte[] b) {
  if (a.Length != b.Length) return false;
  int len = a.Length;
  unsafe {
    fixed (byte* ap = a, bp = b) {
      long* alp = (long*)ap, blp = (long*)bp;
      for (; len >= 8; len -= 8) {
        if (*alp != *blp) return false;
        alp++;
        blp++;
      }
      byte* ap2 = (byte*)alp, bp2 = (byte*)blp;
      for (; len > 0; len--) {
        if (*ap2 != *bp2) return false;
        ap2++;
        bp2++;
      }
    }
  }
  return true;
}

答案 1 :(得分:12)

如果性能真的很重要,那么最快的方法是使用每个版本的Windows附带的CRT库。这段代码在我的poky笔记本电脑上需要大约51毫秒,也适用于64位机器:

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;

class Program {
  static void Main(string[] args) {
    byte[] arr1 = new byte[50 * 1024 * 1024];
    byte[] arr2 = new byte[50 * 1024 * 1024];
    var sw = Stopwatch.StartNew();
    bool equal = memcmp(arr1, arr2, arr1.Length) == 0;
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
    Console.ReadLine();
  }
  [DllImport("msvcrt.dll")]
  private static extern int memcmp(byte[] arr1, byte[] arr2, int cnt);
}

答案 2 :(得分:1)

来自:http://www.pinvoke.net/default.aspx/msvcrt.memcmp: memcmp的下述签名(由Saar)是仅x64签名。在x86计算机上仅使用x64签名将导致PInvoke堆栈不平衡。对于x86和x64平台兼容性,请确保使用指定Cdecl调用约定的签名,并使用UIntPtr类型正确编组size_t count参数:

    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int memcmp(byte[] b1, byte[] b2, UIntPtr count);

    static bool doImagesMatch(byte[] b1, byte[] b2) 
    {     
        return b1.Length == b2.Length && memcmp(b1, b2, new UIntPtr((uint)b1.Length)) == 0;
    } 

我成功使用此代码但我没有时间衡量性能(尚未)。我正在使用大约600字节的小数组。我必须使用与x86兼容的代码,因为我们的非营利组织中的绝大多数计算机都是x86。

显然你需要一个快速的algorhythm来将位图转换为byte []。

答案 3 :(得分:0)

[的DllImport( “MSVCRT.DLL”)]         unsafe static extern int memcmp(void * b1,void * b2,long count);

    unsafe static int ByteArrayCompare1(byte[] b1, int b1Index, int b1Length, byte[] b2, int b2Index, int b2Length)
    {
        CompareCount++;
        fixed (byte* p1 = b1)
        fixed (byte* p2 = b2)
        {
            int cmp = memcmp(p1 + b1Index, p2 + b2Index, Math.Min(b1Length, b2Length));
            if (cmp == 0)
            {
                cmp = b1Length.CompareTo(b2Length);
            }

            return cmp;
        }
    }