比較する配列の種類ごとに個別の P/Invoke フロントエンドを作成できます。T に特化したくないのはわかっていますが、オーバーヘッドはそれほど大きくないと思います。
同じ API 関数に対して異なる署名を持つ複数の P/Invoke メソッドを定義しているため、これは少しハックですが、これを行うことで、P/Invoke マーシャリング サポートを活用できます。
(memcmp からの戻り値の符号は、ソース データが実際にバイトの配列である場合にのみ意味があることに注意してください。int の配列を指定する場合は、戻り値をゼロとのみ比較し、その符号を無視する必要があります。それが意味する順序付けは、int には意味がありません。)
たとえば、次のコードは次のように出力します (デバッグ ビルドではなくリリース ビルド)。
MemCmp with ints took 00:00:08.0768666
ManagedMemCmp with ints took 00:00:10.3750453
MemCmp with bytes took 00:00:01.8740001
ManagedMemCmp with bytes took 00:00:09.2885763
byte[] テストはバイトを使用しているため、int[] テストが使用するバイト数の 4 分の 1 を比較していることに注意してください。マネージ コードは同じ数の比較を行うため、比較的遅くなります。
int の配列を比較する時間には大きな違いはありませんが、バイトの配列を比較する時間には大きな違いがあります。これは、一度に 4 バイトを比較するために、 fixedを使用してバイト配列から int へのポインターを取得する管理された最適化がある可能性があることを示唆しています (最後に収まらない余分なバイトをいじる必要があります)。 int に)。
また、マルチスレッド マネージド バージョン (「int*」最適化を使用してバイト配列を比較する) を作成できると思います。これは、もちろんマルチスレッド化されていないアンマネージド memcmp() よりもはるかに高速です (私の知る限り)。
とにかく、これが私のテストコードです。デバッグではなく、ビルドをリリースすることを忘れないでください。
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Demo
{
public static class Program
{
private static void Main(string[] args)
{
int[] a1 = new int[1000000];
int[] a2 = new int[1000000];
for (int i = 0; i < a1.Length-1; ++i)
{
a1[i] = i;
a2[i] = i;
}
a1[a1.Length-1] = 1;
a2[a1.Length-1] = 2;
byte[] b1 = new byte[1000000];
byte[] b2 = new byte[1000000];
for (int i = 0; i < b1.Length-1; ++i)
{
b1[i] = (byte)i;
b2[i] = (byte)i;
}
b1[a1.Length-1] = 1;
b2[a1.Length-1] = 2;
Stopwatch sw = Stopwatch.StartNew();
testWithMemCmp(a1, a2);
sw.Stop();
Console.WriteLine("MemCmp with ints took " + sw.Elapsed);
sw.Restart();
testWithManagedMemCmp(a1, a2);
sw.Stop();
Console.WriteLine("ManagedMemCmp with ints took " + sw.Elapsed);
sw.Restart();
testWithMemCmp(b1, b2);
sw.Stop();
Console.WriteLine("MemCmp with bytes took " + sw.Elapsed);
sw.Restart();
testWithManagedMemCmp(b1, b2);
sw.Stop();
Console.WriteLine("ManagedMemCmp with bytes took " + sw.Elapsed);
}
private static void testWithMemCmp(int[] a1, int[] a2)
{
for (int j = 0; j < COUNT; ++j)
{
MemCmp(a1, a2);
}
}
private static void testWithMemCmp(byte[] a1, byte[] a2)
{
for (int j = 0; j < COUNT; ++j)
{
MemCmp(a1, a2);
}
}
private static void testWithManagedMemCmp(int[] a1, int[] a2)
{
for (int j = 0; j < COUNT; ++j)
{
ManagedMemCmp(a1, a2);
}
}
private static void testWithManagedMemCmp(byte[] a1, byte[] a2)
{
for (int j = 0; j < COUNT; ++j)
{
ManagedMemCmp(a1, a2);
}
}
public static bool ManagedMemCmp(int[] a1, int[] a2)
{
if (a1 == null || a2 == null || a1.Length != a2.Length)
{
throw new InvalidOperationException("Arrays are null or different lengths.");
}
for (int i = 0; i < a1.Length; ++i)
{
if (a1[i] != a2[i])
{
return false;
}
}
return true;
}
public static bool ManagedMemCmp(byte[] a1, byte[] a2)
{
if (a1 == null || a2 == null || a1.Length != a2.Length)
{
throw new InvalidOperationException("Arrays are null or different lengths.");
}
for (int i = 0; i < a1.Length; ++i)
{
if (a1[i] != a2[i])
{
return false;
}
}
return true;
}
public static bool MemCmp(byte[] a1, byte[] a2)
{
if (a1 == null || a2 == null || a1.Length != a2.Length)
{
throw new InvalidOperationException("Arrays are null or different lengths.");
}
return memcmp(a1, a2, new UIntPtr((uint)a1.Length)) == 0;
}
public static bool MemCmp(int[] a1, int[] a2)
{
if (a1 == null || a2 == null || a1.Length != a2.Length)
{
throw new InvalidOperationException("Arrays are null or different lengths.");
}
return memcmp(a1, a2, new UIntPtr((uint)(a1.Length * sizeof(int)))) == 0;
}
[DllImport("msvcrt.dll")]
private static extern int memcmp(byte[] a1, byte[] a2, UIntPtr count);
[DllImport("msvcrt.dll")]
private static extern int memcmp(int[] a1, int[] a2, UIntPtr count);
private const int COUNT = 10000;
}
}