这是我所知道的最快的方法。它确实有它的缺点。就像火箭一样,你不希望它在你的车上,但它有它的位置。就像您需要设置结构并在管道的两端具有相同的结构一样。结构体需要固定大小,否则会比这个例子复杂。
这是我在我的机器上获得的性能(i7 920,12gb ram)发布模式,没有附加调试器。在测试期间它使用 100% cpu,所以这个测试是 CPU bound。
Finished in 3421ms, Processed 52.15 GB
For data write rate of 15.25 GB/s
Round trip passed
.. 和代码...
class Program
{
unsafe
static void Main(string[] args)
{
int arraySize = 100;
int iterations = 10000000;
ms[] msa = new ms[arraySize];
for (int i = 0; i < arraySize; i++)
{
msa[i].d1 = i + .1d;
msa[i].d2 = i + .2d;
msa[i].d3 = i + .3d;
msa[i].d4 = i + .4d;
msa[i].d5 = i + .5d;
msa[i].d6 = i + .6d;
msa[i].d7 = i + .7d;
}
int sizeOfms = Marshal.SizeOf(typeof(ms));
byte[] bytes = new byte[arraySize * sizeOfms];
TestPerf(arraySize, iterations, msa, sizeOfms, bytes);
// lets round trip it.
var msa2 = new ms[arraySize]; // Array of structs we want to push the bytes into
var handle2 = GCHandle.Alloc(msa2, GCHandleType.Pinned);// get handle to that array
Marshal.Copy(bytes, 0, handle2.AddrOfPinnedObject(), bytes.Length);// do the copy
handle2.Free();// cleanup the handle
// assert that we didnt lose any data.
var passed = true;
for (int i = 0; i < arraySize; i++)
{
if(msa[i].d1 != msa2[i].d1
||msa[i].d1 != msa2[i].d1
||msa[i].d1 != msa2[i].d1
||msa[i].d1 != msa2[i].d1
||msa[i].d1 != msa2[i].d1
||msa[i].d1 != msa2[i].d1
||msa[i].d1 != msa2[i].d1)
{passed = false;
break;
}
}
Console.WriteLine("Round trip {0}",passed?"passed":"failed");
}
unsafe private static void TestPerf(int arraySize, int iterations, ms[] msa, int sizeOfms, byte[] bytes)
{
// start benchmark.
var sw = Stopwatch.StartNew();
// this cheats a little bit and reuses the same buffer
// for each thread, which would not work IRL
var plr = Parallel.For(0, iterations/1000, i => // Just to be nice to the task pool, chunk tasks into 1000s
{
for (int j = 0; j < 1000; j++)
{
// get a handle to the struc[] we want to copy from
var handle = GCHandle.Alloc(msa, GCHandleType.Pinned);
Marshal.Copy(handle.AddrOfPinnedObject(), bytes, 0, bytes.Length);// Copy from it
handle.Free();// clean up the handle
// Here you would want to write to some buffer or something :)
}
});
// Stop benchmark
sw.Stop();
var size = arraySize * sizeOfms * (double)iterations / 1024 / 1024 / 1024d; // convert to GB from Bytes
Console.WriteLine("Finished in {0}ms, Processed {1:N} GB", sw.ElapsedMilliseconds, size);
Console.WriteLine("For data write rate of {0:N} GB/s", size / (sw.ElapsedMilliseconds / 1000d));
}
}
[StructLayout(LayoutKind.Explicit, Size= 56, Pack=1)]
struct ms
{
[FieldOffset(0)]
public double d1;
[FieldOffset(8)]
public double d2;
[FieldOffset(16)]
public double d3;
[FieldOffset(24)]
public double d4;
[FieldOffset(32)]
public double d5;
[FieldOffset(40)]
public double d6;
[FieldOffset(48)]
public double d7;
}