让 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 分配到 domain memor
- 在 ByteArray 分配到 domain memory 之前需要设定它的长
- 为了保证最大限度地提升性能,请尝试直接使用 load/store 指令,而不要再用 AS 函数封装它们
- load 指令总要赋值给一个变量。不做任何操作会导致一个 Verify Error,而且这是当前一个已知的 BUG
下面的例子展示普通的 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 倍。