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


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

      先定义假想的一个值类型:

    Code

      然后,定义一个公用方法签名:Action<MyStruct, Stream>,这个是为了方便之后的几种不同方式做性能测试。

      先来看看Marshal类是怎么做到的:

    Code

      然后看看unsafe代码是如何做到的:

    Code

      比较两者,可以发现,使用Marshal类出现了装箱,新建数组(因为签名定成了输出到流),分配堆空间,和释放对空间等,当然,实战中可以避免掉新建数组的代价,但是总体代价依然高于unsafe方法,当然,用Marshal可以很轻松的做到把任意值类型copy到数组里面,这一点上unsafe方法就吃亏了,因为unsafe方法必须要非常明确的支出结构体的具体类型。

      先来看一个性能对比:

    Code

      在我机器(型号比较老。。。)上的运行结果是:135,718

    可以发现unsafe代码的性能优势非常明显,但是,如果不解决类型问题,unsafe的方式显然实用意义仍然小与Marshal方式,可能有人会想到用泛型,但是不幸的是泛型无法作用于unsafe代码,也就是说,T*是无法通过编译的,难道真的走投无路了吗?

      别忘了,.net还有一个杀手锏,LCG——轻量级代码生成,就是凭借LCG,IronPython的性能才能如此出众。我们无法在运用泛型指针,但是我们可以用泛型方法来生成对应类型的非泛型unsafe代码,来实现一个:

    Code

      有点长,但是性能如何哪?来改造一下测试代码:

    Code

      看看结果如何:136,713,142

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

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

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

      如果,无论次数多少,都要求最高性能的话,那就只有用unsafe的方法,把每一个需要用到的结构体都写一遍了,就是用人力换速度。。。

  • 相关阅读:
    第10组 Beta冲刺(4/5)
    第10组 Beta冲刺(5/5)
    第10组 Beta冲刺(3/5)
    第10组 Beta冲刺(2/5)
    第10组 Beta冲刺(1/5)
    第10组 Alpha事后诸葛亮
    第10组 Alpha冲刺(6/6)
    第10组 Alpha冲刺(5/6)
    软工实践个人总结
    第09组 Beta版本演示
  • 原文地址:https://www.cnblogs.com/LinFx/p/2123686.html
Copyright © 2020-2023  润新知