ActionScript 3.0程式最佳化(一)以及Vector資料類型簡介
ActionScript 3.0程式最佳化(一)以及Vector資料類型簡介
譯∕趙英傑
本文摘譯自Armand Niculescu撰寫的AS3 Performance Optimization,筆者再加註一段Vector資料類型的說明。
多數的Flash應用程式都不需要替程式做最佳化(對岸稱為「优化」)處理,所以最好把開發時間花在其他方面。通常只有像下列程式在執行效能上遇到瓶頸時,才需要做最佳化處理:
- 3D動畫
- 複雜的物理運算
- 編碼(encoding)和加密(encryption)
- AI(人工智慧,如:最佳路徑搜尋)
不必太早考量最佳化
不要在著手編寫程式時,就想著如何最佳化程式。這是非常普遍的錯誤,當你開始製作專案時,應該要集中精力解決功能面的問題,而不是最佳化。應該要撰寫清晰的程式碼以及說明文件,並且確保程式能正常運作而非快速執行。大型的應用程式都會在開發期間發現一些問題(bug),而且經常會為了解決程式問題而延長除錯(debug)的時間。
始終設定變數的類型
最佳化的首要技巧就是始終替變數設定資料類型。這對於處理陣列元素的速度提升尤其顯著,因為ActionScript的陣列元素可以儲存任意類型的資料,而Flash內部的AVM(ActionScript虛擬機器)勢必要在處理它們之前做一些確認工作。
以底下的程式片段為例:
var crtPiece:int = movesArray[i].piece;
如果將它改寫成:
var crtMove:Move = movesArray[i]; var crtPiece:int = crtMove.piece;
將能獲得顯著的速度提升。同樣地,底下的程式片段:
var element:int = matrix[i][j];
可以被改寫成:
var row:Array = matrix[i]; var element:int = row[j];
此外,假定用戶採用Flash Player 10,你可以把上面的兩個例子分別用Vector(參閱下文「Vector資料類型簡介」一節說明)改寫成:
var movesArray:Vector.<Move>;
以及:
var matrix:Vector.<Vector.<int>>;
這樣就不需要多寫一行程式了。
附帶說明,假如你已經採用改寫的Array版本,就不需要改成Vector的形式,因為兩者的執行效率差不多。
不要使用常數
這是我從 Adobe 的 Flash Player 工程師那裡得到的技巧。我總認為當編譯器遇到底下的程式碼定義時:
public const NAME:String = "foo";
將會把其中的常數替換成指定的數值。不過,事實並非如此。
常數有助於讓程式碼保持乾淨與可讀性,所以我之前才說只有在絕對必要時,再著手最佳化程式。
在製作棋盤遊戲時,我使用常數來儲存一些數值,例如:WHITE_PAWN,甚至用常數記錄棋格(如:A1或H8)。若直接用資料值取代常數,將會降低程式的可讀性,例如:if (pieceType==3) or if (targetSquare==7) 並不直觀易讀,但是將能顯著地改善運算效能。
降低呼叫函數的次數
這是另一個痛苦的抉擇。我在多年前看過一段C程式碼,不了解為何程式設計師要定義一些複雜的巨集(macro),像是:
#define MIN(a,b) ((a)<(b) ? (a) : (b))
而不寫成函數。
這是因為巨集比較快。如果你需要呼叫一個簡單的函數100,000次,把函數內容直接放在程式內執行,會比較快。尤其是Math類別的函數。你可以把底下的敘述:
var x:int = Math.min(a,b)
改寫成:
var x:int = (a<b) ? a : b;
每當我刪掉了一些執行轉換或者簡單數學運算的簡短函數(1-2行)後,運算速度就增加約 10 - 15%。
同樣地,最好也不要使用Array的方法,像是push(), pop(), shift()或unshift();你可以多寫一點程式碼來換得較好的執行效能。
使用int(整數)類型以及bitwise(位元)運算子
處理整數資料時,請使用int。unit 並不會提升陣列索引的速度,因此,除非你真的需要使用 uint,否則就用 int。
bitwise(位元)運算子比起一般的數學操作運算,快了2到10倍。底下的乘、除運算:
var x:int = a*2; var y:int = b*16; var z:int = c/4;
可改寫成:
var x:int = a << 1; //2^1 = 2; var y:int = b << 4; //2^4 = 16; var z:int = c >> 2; //2^2 = 4;
餘除(modulo,也就是 % 運算子)的運算式:
if (n % x == 0)
可改寫成:
if (n & (x-1) == 0)
預先計算∕暫存結果
Math類別的方法,像sin(), ln(), sqrt()的效能不佳,而且程式可能需要一再使用到這些相同的數值,這個時候,你可以先儲存這些計算結果,讓程式以「查表」的方式取得值。例如,把Math.sin()函數的值存入sine陣列,需要計算Math.sin(25)的值時,只要讀取sine[25]的值即可。
Vector資料類型簡介
簡單的說,Vector(直譯為「向量」)就是具有資料類型設定的陣列(Array),就語法而言,除了宣告變數的指令格式不同之外,Vector提供的方法(method)和陣列是一樣的。從功能面來看,Vector 和陣列的兩個主要不同點在於,Vector 類型可以設定成固定大小;陣列資料允許元素中間有空白的元素,而Vector的每個索引元素都必須要有值(或是 null)。最後,Flash Player 10或更新版本才支援Vector類型資料。
Vector類型資料的宣告語法範例如下,它採用後設資料類型宣告,緊接在Vector類型後面加上一個點(.),再用小於和大於符號標示資料格式(如:int, String,…):
var intVec:Vector.<int> = new Vector.<int>();
上面的敘述宣告了一個叫做 intVec 的Vector類型變數,其元素只能是 int(整數)類型;底下的敘述則宣告了一個長度固定為10的Vector變數:
var intVec:Vector.<int> = new Vector.<int>(10, true);
Vector的操作方式和陣列一樣,例如,在intVec的第0個元素存入100的敘述如下:
intVec[0] = 100;
關於 Vector 變數的其他說明,請參閱 Adobe 的線上說明文件。