让 ByteArray 更快

原文:Making ByteArray faster
作者:Romil Mittal
翻译:dreamana.com

FlasCC (之前叫 Alchemy) 生成的 ActionScript 字节码 (简称 .abc) 比起用 ActionScript 编译器实现的性能更好。除了因为用了更好的数据类型和指令之外,背后的一个主要原因是 FlasCC 使用了 domain memory,使其在内存缓冲区中读写速度更快。Flash 与 AIR Runtime 已经支持这些特殊的内存操作码去使用 domain memory 提高内存访问速度。

从 AIR 3.6 开始,ActionScript 编译器 2.0 (ASC2) 能够直接从 AS3 代码编译出这些快速内存操作码了(之前只能通过 FlasCC 实现)。

让 ByteArray 更快,你只需将它分配(赋值)到 domainmemory

ApplicationDomain.currentDomain.domainMemory = myByteArray;

再加上一个新增的包,叫 avm2.intrinsics.memory,提供了从快速 Bytearray 中存取数据指令:

package avm2.intrinsics.memory {

    public function li8(addr:int):int; // load 8 bit int
    public function li16(addr:int):int; // load 16 bit int
    public function li32(addr:int):int; // load 32 bit int
    public function lf32(addr:int):Number; // load 32 bit float
    public function lf64(addr:int):Number; // load 64 bit float

    public function si8(value:int, addr:int):void; // store 8 bit integer
    public function si16(value:int, addr:int):void; // store 16 bit integer
    public function si32(value:int, addr:int):void; // store 32 bit integer
    public function sf32(value:Number, addr:int):void; // store 32 bit float
    public function sf64(value:Number, addr:int):void; // store 64 bit float

    public function sxi1(value:int):int; // sign extend a 1 bit value to 32 bits
    public function sxi8(value:int):int; // sign extend an 8 bit value to 32 bits
    public function sxi16(value:int):int; // sign extend a 16 bit value to 32 bits
}

这里有一些要注意的地方:

下面的例子展示普通的 ByteArray 的用法,以及怎样使它更快:

package
{
    import flash.display.Sprite;
    import flash.system.ApplicationDomain;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;

    import avm2.intrinsics.memory.li8;
    import avm2.intrinsics.memory.si8;

    public class DomainMemoryTest extends Sprite
    {
        private var BYTE_ARRAY_SIZE:Number = 10000000;
        private var resultsDisplay:TextField = new TextField();
        private var normalByteArrayTime:uint = 0;
        private var fastByteArrayTime:uint = 0;

        public function DomainMemoryTest()
        {
            super();   
            setupDisplay();
            timeNormalByteArray();
            timeFastByteArray();

            resultsDisplay.appendText("\nFast ByteArray is " + (normalByteArrayTime - fastByteArrayTime).toString() + " milliseconds faster.");
        }

        // Write and Read 'numInts' integers in/from the bytearray

        private function timeNormalByteArray() : void
        {
            var ba:ByteArray = new ByteArray();

            var i:int = 0;

            var startTimer:int = getTimer();

            for(i=0; i<BYTE_ARRAY_SIZE; i++)
            {
                ba.writeByte(100);
            }

            ba.position = 0;

            for(i=0; i<BYTE_ARRAY_SIZE; i++)
            {
                ba.readByte();
            }

            var endTimer:int = getTimer();

            normalByteArrayTime = endTimer - startTimer;
            resultsDisplay.appendText("Time to write and read normal ByteArray: " + normalByteArrayTime.toString());
        }

        private function timeFastByteArray () : void
        {
            var ba:ByteArray = new ByteArray();

            // Set the size of bytearray
            ba.length = BYTE_ARRAY_SIZE;

            ApplicationDomain.currentDomain.domainMemory = ba;

            var i:int = 0;
            var valueLoadedFromByteArray:int = 0;          

            var startTimer:int = getTimer();

            for(i=0; i<BYTE_ARRAY_SIZE; i++)
            {
                si8(100, i);
            }
            for(i=0; i<BYTE_ARRAY_SIZE; i++)
            {
                valueLoadedFromByteArray = li8(i);
            }

            var endTimer:int = getTimer();

            fastByteArrayTime = endTimer - startTimer;
            resultsDisplay.appendText("\nTime to write and read fast ByteArray: " + fastByteArrayTime.toString());
        }

        private function setupDisplay():void
        {
            resultsDisplay.x = 10;
            resultsDisplay.y = 10;
            resultsDisplay.border = true;
            resultsDisplay.multiline = true;
            resultsDisplay.wordWrap = true;
            resultsDisplay.autoSize = TextFieldAutoSize.LEFT;
            resultsDisplay.width = 400;
            addChild(resultsDisplay);
        }

    }
}

运行以上代码对比性能得出一下结果:

Normal ByteArray Fast ByteArray
Macbook Pro (2.6 GHz, 16GB) 3510 ms 1755 ms
iPhone 3GS 53600 ms 23800 ms

结果表明,使用了 domain memory 比普通的 ByteArray 几乎快了 2 倍。