XML のパース速度を環境を変えて測定してみたところ、面白い結果が出てきたので、まとめてみました。
XMLデータ
測定に使った XML は次のようなシンプルなものです。単純ですが、Web API の出力として、よく用いられる形です。
<root>
<result>1</result>
<items>
<item>http://www.example.com/?e0fe16290dc90f4e929bb4f72973c4ce</item>
<item>http://www.example.com/?150f9f8df8b51d7feb61999623f4ea0b</item>
:
<item>http://www.example.com/?a7d3bd66e2eb279d789f34efb6f8a9ac</item>
</items>
</root>
JavaScript でのパース
まず、JavaScript の処理速度を測ってみました。
パースする部分は XMLHttpRequest を使って次のように書きました。
xmlhttp.open("GET", url, false);
xmlhttp.send(null);
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var root = xmlhttp.responseXML.documentElement;
var itemContainer = root.getElementsByTagName("items")[0];
var items = itemContainer.getElementsByTagName("item");
var len = items.length;
for(var i = 0; i < len; i++){
var s = items[i].firstChild.nodeValue;
}
}
XML の item タグの個数が増えるにしたがって、各ブラウザの処理速度にどのように違いが出てくるかを調べました。
意外にも(?) Firefox が一番遅く、IE が一番速いという結果になりました。
試験を行った端末は Pentium 4 3.00GHz、メモリ 2.00GB です。サーバーは localhost に立てた Web サーバー AN HTTP Daemon を用いました。XML ファイルのサイズは、256ノードが19KB、512ノードが37KB、1024ノードが74KB、2048ノードが147KB、4096ノードが293KB、8192ノードが585KB、16384ノードが1,169KB、32768ノードが2,337KB です。
それぞれの特徴を分析してみます。
- Internet Explorer
- ダウンロードとパースに要した時間の短さが光ります。
- Firefox
- ループの部分には、かなりの時間を要しています。
- Opera
- ループの速さが際立ちます。ダウンロード+パースに時間がかかっていますが、後の検証でも分かるのですが、Opera のダウンロード性能はIEと同程度であるため、パースに時間がかかっていると想定できます。パースに時間がかかった分、DOM 操作は速いので、パース時に何らかのインデックス化を行っているのかもしれません。
その他の気づいたことをまとめます。
- IE6・FF1.5 と1世代前のブラウザで測定していますが、IE7・FF2 で測定しても同じ傾向でした。
- Firefox は safe mode で測定しました。通常起動するとエクステンションの影響なのか、処理速度は約2割増になりました。
- Donut RAPT(IE コンポーネントを利用したブラウザ)では、ループの処理に IE の3倍の時間を要しました。それでも、Firefox の 2/3 程度の時間です。
- どのブラウザでも getElementsByTagName に時間を要していないのが意外でした。XML パース時にタグ名でハッシュを作成しているのでしょうか。
ActionScript でのパース
次に、先ほどの JavaScript を ActionScript 3.0 に移植して、速度の変化を調べました。
getElementsByTagName に相当するところは、E4X の .. 演算子(getElementsByTagName に相当)を利用しています。
var loader:URLLoader = new URLLoader();
var req:URLRequest = new URLRequest(url);
loader.addEventListener(Event.COMPLETE, function(e:Event):void
{
var root:XML = XML(loader.data);
if(!root) return;
var itemContainer:XML = root..items[0];
var items:XMLList = itemContainer..item;
var len:int = items.length();
var arr:Array = [];
for each(var x:XML in items){
var s:String = x.text();
}
});
Flex SDK 2.0.1 の mxmlc でコンパイルし、item ノードの個数を変えてブラウザごとに測定しました。環境は JavaScript の試験と同じです。
各ブラウザとも、かなり処理が速くなっています。(先ほどの縦軸最大値は1.5秒でしたが、今回は0.5秒である点に注意してください)
Flash プレイヤーが実行しているからでしょうか、パース以降の処理は、ほとんど処理速度に違いがありません。Flash プレイヤーはブラウザにダウンロード処理を任せているため、ダウンロードに要する時間はブラウザによって違いがあります。Firefox の遅さが際立っています。
XML のループ部分があまりに早かったので、コンパイル時に最適化されているのではないかと疑いましたが、item ノード中の文字列を加えていく処理を実装しても、処理時間は約1.5倍になる程度でした。
トータル時間の比較
3つのブラウザ、JS/AS それぞれで、ロードからループ処理までにかかった時間を比較しました。
まとめ
- JavaScript より ActionScript のほうが速い(バイトコードなので当たり前といえば、当たり前)。
- JavaScript の XML 処理は、実は Firefox が一番遅い
- IE と Opera は処理が複雑になれば、Opera のほうが速くなると予想される
間違いの指摘や検証は大歓迎です。今回の試験に用いたファイルは こちらからダウンロード できます。また、ブラウザ上でテストしてみたい方は こちらから試してみてください (環境によっては数秒~数十秒間、ブラウザが応答しなくなるのでご注意ください)。
将来展望
大きな XML ファイルを扱う場合には、XML パーサーだけを ActionScript にしてみても面白いかもしれません。その場合、JavaScript と ActionScript の通信部分(ExternalInterface)のオーバーヘッドを調査する必要があります。