您的位置:首页 > 其它

结构体转换成对应的byte数组

2010-05-25 17:03 344 查看
最近看到一个帖子,问的是怎么把自己定义的结构体转换成对应的byte数组,一般来说,都会想到用Marshal类来完成这个功能,其实还有一个方法也可以,那就是利用unsafe代码。
  先定义假想的一个值类型:

static void Main()
{
MyStruct s = new MyStruct();
s.Low = 5;
s.Hi = 10;
s.X = 1;
const int count = 1000000;
MemoryStream ms = new MemoryStream();
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < count; i++)
ByUnsafe(s, ms);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
ms = new MemoryStream();
GC.Collect(2);
GC.WaitForPendingFinalizers();
sw.Reset();
sw.Start();
for (int i = 0; i < count; i++)
ByMarshal(s, ms);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
ms = new MemoryStream();
GC.Collect(2);
GC.WaitForPendingFinalizers();
sw.Reset();
sw.Start();
var d = ByLcg<MyStruct>();
for (int i = 0; i < count; i++)
d(s, ms);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}


1 public static Action<T, Stream> ByLcg<T>()
2 where T : struct
3 {
4 DynamicMethod dm = new DynamicMethod(string.Empty, typeof(void),
5 new Type[] { typeof(T), typeof(Stream) }, typeof(T));
6 var il = dm.GetILGenerator();
7 var ptr = il.DeclareLocal(typeof(T).MakePointerType());
8 var i = il.DeclareLocal(typeof(int));
9
var loopCondition = il.DefineLabel();
var loopBegin = il.DefineLabel();

il.Emit(OpCodes.Ldarga_S, 0);
il.Emit(OpCodes.Conv_U);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Br_S, loopCondition);
il.MarkLabel(loopBegin);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Ldind_U1);
il.Emit(OpCodes.Callvirt, typeof(Stream).GetMethod("WriteByte"));
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc_1);
il.MarkLabel(loopCondition);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Sizeof, typeof(T));
il.Emit(OpCodes.Clt);
il.Emit(OpCodes.Brtrue_S, loopBegin);
il.Emit(OpCodes.Ret);

return (Action<T, Stream>)dm.CreateDelegate(typeof(Action<T, Stream>));
}
  看看结果如何:136,713,142

  真的这么强大吗?LCG本身的代价哪?可以把count修改成1,再次运行,得到的结果是:0,0,14

  也可以看到在循环次数太少的情况下,获得的性能优势不足以弥补LCG本身的消耗,那么多少是临界点哪?

  我的机器上,经过多次试验,发现21000时,Marshal方法和LCG方法的时间消耗相等,也就是说,当次数小于21000次是,Marshal占了上风,单是如果,超过21000次时,LCG带来的性能优势,就足以弥补代码生成的损失了。(当然,前提是生成的代码,以委托的方式被缓存下来)

  如果,无论次数多少,都要求最高性能的话,那就只有用unsafe的方法,把每一个需要用到的结构体都写一遍了,就是用人力换速度。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: