我正在寻找性能高效的方法来比较两个字节[]是否相等。尺寸大于1MB,所以每个数组元素的开销应该最小化。没有绑定检查的C#字节[]比较
我的目标是打败SequenceEqual
或hand-coded for-loop over every item,通过avoiding the repetitive bound checks两个阵列的速度。如同Array.Copy
可能导致快速memcpy
一样,什么会导致memcmp
?
我正在寻找性能高效的方法来比较两个字节[]是否相等。尺寸大于1MB,所以每个数组元素的开销应该最小化。没有绑定检查的C#字节[]比较
我的目标是打败SequenceEqual
或hand-coded for-loop over every item,通过avoiding the repetitive bound checks两个阵列的速度。如同Array.Copy
可能导致快速memcpy
一样,什么会导致memcmp
?
如果性能真的很重要,然后做到这一点是通过使用包含在每个版本的Windows CRT库的最快方法。此代码发生在我的笔记本电脑狭小〜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);
}
+1。还有其他的东西,比如CRT版本中可能考虑的内存对齐。不要在不安全的代码中重新发明轮子是要走的路。当然,只有在分析并证明它是值得的 - 标准免责声明之后。 – 2010-01-31 22:24:51
+1。使用经过良好测试的优化程序比使用自己的程序更好,希望它能以某种方式在您碰巧运行的任何平台上快速运行。 – 2010-01-31 22:43:06
别忘了将阵列固定到位! – 2010-02-22 18:53:52
您可以使用不安全的代码来执行指针操作。您可以一次为整数比较字节四:
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;
}
一个测试,这对一个简单的循环,而且速度更快,约六倍。根据乔什·爱因斯坦的建议,long可以在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;
}
函数[DllImport( “MSVCRT.DLL”) 不安全的静态外部INT memcmp(void *的B1,无效* B2 ,长计);
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;
}
}
来自:http://www.pinvoke.net/default.aspx/msvcrt.memcmp:memcmp的 Belowmentioned签名(由萨尔)是仅x64签名。在x86机器上使用x64 only签名会导致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。
显然你需要一个快速的算法将位图转换为byte []。
你需要比较两个块还是一个块?也许如果你更多地告诉我们你正在做的这个场景,甚至可以找到更好的解决方案?例如,如果您需要将块序列与许多其他块进行比较,那么一个简单的散列函数至少会为您提供很多保证的差异,并且只需很少的工作,然后您就可以专注于潜在的误报。 – 2010-01-31 22:39:06