脚本到二进制转换&对象序列化

时间:2013-12-03 14:47:02

标签: c++ actionscript-3 flash serialization scripting

我编写的所有代码(C ++或AS3)都是大量编写的(JSON或XML)。我的问题是解析有时可能非常慢,特别是对于像手机这样功能较弱的设备。

以下是我的Flash脚本示例:

        <players class="fanlib.gfx.TSprite" vars="x=0|y=-50|visible=Bool:true">
            <player0 class="fanlib.gfx.TSprite" vars="x=131|y=138">
                <name class="fanlib.text.TTextField" format="Myriad Pro,18,0xffffff,true,,,,,center,,,,0" alignX="center" alignY="bottom" filters="DropShadow,2" vars="background=Bool:false|backgroundColor=0|embedFonts=Bool:true|multiline=Bool:false|mouseEnabled=Bool:false|autoSize=center|text=fae skata|y=-40"/>
                <avatar class="fanlib.gfx.FBitmap" alignX="center" alignY="center" image="userDefault.png"/>
                <chip class="fanlib.gfx.FBitmap" alignX="center" alignY="center" image="chip1.png" vars="x=87|y=68"/>
                <info class="fanlib.text.TTextField" format="Myriad Pro,18,0xffffff,true,,,,,center,,,,0" alignX="center" alignY="top" filters="DropShadow,2" css=".win {color: #40ff40}" vars="y=40|background=Bool:false|backgroundColor=0|embedFonts=Bool:true|multiline=Bool:false|mouseEnabled=Bool:false|autoSize=center"/>
            </player0>

            <player1 class="Copy:player0" vars="x=430|y=70">
                <chip class="Child:chip" image="chip2.png" vars="x=-82|y=102"/>
            </player1>
            <player2 class="Copy:player0" vars="x=778|y=70">
                <chip class="Child:chip" image="chip3.png" vars="x=88|y=103"/>
            </player2>
            <player3 class="Copy:player0" vars="x=1088|y=137">
                <chip class="Child:chip" image="chip4.png" vars="x=-111|y=65"/>
            </player3>
            <player4 class="Copy:player0" vars="x=1088|y=533">
                <chip class="Child:chip" image="chip5.png" vars="x=-88|y=-23"/>
            </player4>
            <player5 class="Copy:player0" vars="x=585|y=585">
                <chip class="Child:chip" image="chip6.png" vars="x=82|y=-54"/>
            </player5>
            <player6 class="Copy:player0" vars="x=117|y=533">
                <chip class="Child:chip" image="chip7.png" vars="x=85|y=-26"/>
            </player6>
        </players>

上面的脚本创建了“本机”(如“非动态”)Flash对象。 TSprite是一个Sprite后代,FBitmap继承自Bitmap等。在71KB上,在我的Sony XPeria上解析需要几十秒。

而不是优化解析器(无论如何都不会获得太多)我正在考虑将我的脚本转换为二进制文件,以便脚本将用于调试和已发布的代码的最终二进制文件。

一个问题是,在序列化时,如何处理从一个对象到另一个对象的指针?如何将指针从内存转换为磁盘文件友好格式,然后再转回内存?

另一个问题是,“嵌套”对象怎么样?例如,在Flash中,对象可以是其他对象的图形容器。这样的状态可以序列化吗?或者必须单独保存对象,并且从磁盘加载时,通过嵌套函数(即addChild等...)添加到父对象中?

如果可能的话,我希望通用指南适用于与C ++或AS3不同的语言。

2 个答案:

答案 0 :(得分:3)

据我所知,您的想法是通过将对象的创建从一些fixture脚本(xml / json)替换为反序列化(来自二进制)以前序列化的对象来节省一些时间。如果是这样的话,我相信你已经采取了错误的方法来解决这个问题。

既然您已经要求提供一般性指导原则,我会尝试解释我的推理,而不是深入研究语言特定的细节。请注意,我将讨论常见情况,可能会有例外情况。没有灵丹妙药,你应该分析你的场景,为它选择最佳解决方案。

从一个角度来看,基于fixture / script创建一组对象与从二进制中反序列化对象没有什么不同。最后,他们两个都是关于转变一些&#34;浓缩&#34;将状态转换为可以使用的对象。是的,确实二进制文件的大小通常较小但是像JSON这样的格式在 commomon case 中没有那么多开销(但XML通常 更多冗余)。 一般您不会在二进制文件中反序列化这个状态,而不是从脚本中解析,从而节省了大量时间/内存。这是我工作过的一个真实世界的例子:Mental Ray是在电影行业中渲染3D场景\特效的事实标准。它使用textual file format来表示在许多方面与JSON有些相似的场景。 Mental Ray在计算方面很重要,性能是这里的关键问题之一,但它没有二进制场景文件格式,它仍然完美无缺。因此,分析这方面可以说这两种方法之间没有实质性差异。

从另一个角度来看,可能会发挥作用。虽然反序列化对象仅暗示创建对象将状态加载到其字段,但从脚本创建对象可能还包含一些额外的初始化。因此,在某些情况下,使用反序列化方法可能会带来好处。

然而,最后我会争辩说,简单地将脚本对象重新替换为序列化对象并不是一个好主意,因为脚本和序列化在概念上是不同的,并且具有不同的目的(尽管它们确实如此)有共同之处)。使用序列化方法,您将在修改固定状态时失去灵活性(人们通常更难编辑二进制文件而不是JSON / XML)以及执行初始化工作的能力

因此,请考虑您在场景中实际需要的内容并坚持下去。这是最好的方式。

现在,如果碰巧是你真的需要你的对象脚本化,但这种方法不够快我会调查以两种方式之一加速它:

  1. 分析是否可以按照较少的时间加载来重构数据。但这并不总是可行,但值得尝试。

  2. 分析您的脚本引擎对init对象的其他操作,只需创建它们并将状态加载到其字段中并尝试对其进行优化。这种方法实际上具有最大的潜力,因为这是在性能方面(脚本和反序列化方法之间)具有实质性差异的唯一部分,并且不会导致概念的误用。试着看看你是否能够减少init对象所需的工作量。如果您目前正在使用某种通用脚本引擎\框架,那么根据您的需求定制更具体的内容可能是一个好主意。

  3. 现在,回答你原来的问题......

      

    在序列化时如何处理从一个对象到另一个对象的指针?

    引用很令人头疼,大多数序列化实现都不会搞砸。

    其中一种方法是在序列化期间使用某些东西来识别对象(例如指针),序列化对象保留这个标识,并将来自另一个对象的引用存储到该对象,而不是作为基本类型,而是作为引用类型(基本上保存身份)。反序列化时 - 跟踪所有反序列化的对象,并在去参考类型字段时重用它们。

      

    如何将指针从内存转换为磁盘文件格式,然后再转回内存?

    序列化处理原始内存时很少见。这种方法仅适用于原始类型,并且不适用于poiners / reference。支持reflection \ introspection的语言通常使用它来检查字段的值以序列化对象。如果我们谈论纯C ++,其中反射很差 - 除了使对象本身定义将自身序列化为字节流并使用这些方法之外,没有其他可靠的方法。

      

    另一个问题是,&#34;嵌套&#34;对象?例如,在Flash中,对象可以是其他对象的图形容器。这样的状态可以序列化吗?或者必须单独保存对象,并且从磁盘加载时,通过嵌套函数(即addChild等...)添加到父对象中?

    如果我们谈论反序列化 - 这些应该被视为引用(参见上面的答案)。使用像addChild这样的方法并不是一个好主意,因为它可能包含一些会弄乱的东西。

    希望这能回答你的问题。

答案 1 :(得分:1)

你应该看看Adobe Remote Object

通常使用序列化可能会让您遇到问题,例如:

  • 我有一个来自应用程序版本2.3的序列化对象,现在已经修改了新版本2.4:已删除属性/已添加属性。这使我的序列化对象无法解析。
  • 在开发支持跨平台的序列化协议时,您可能希望在调试时自杀。我记得自己这样做了,我花了几个小时才发现我的闪光灯使用Big Indian和C#使用Small Indian。

Adob​​e为您解决了这些问题,他们创建了一个很好的二进制协议,名为AMF - 动作消息格式。它在各种平台上有许多可以与您的动作脚本进行通信的实现。

Here你可能会发现一些C ++实现。