Railsからの応答をE4Xで受信した場合とAMFで受信した場合を比較した。使ったのはidとnameからなる1000行のMySQLデータ。Flexからリクエストしてから応答までの時間を測定したところ、AMFの方が5倍も遅くなって困惑した。環境はFlex SDK 3.0, Ruby 1.8.6, Rails 2.1, MySQL 5.0.45で全て同じローカルマシン内。
Rails側
RubyAMFをインストールしたRailsプロジェクト内にUserモデルとUsersControllerを作成。UserモデルはMySQLのusersテーブル(id, name)とシンクロ済み(テストデータはgeneratedata.comで作成)。UsersControllerに以下のようにindexを記述。
class UsersController < ApplicationController
def index
@users = User.find(:all)
respond_to do |format|
format.xml {render :xml => @users} # For HTTPService
format.amf {render :amf => @users} # For RemoteObject
end
end
end
AMFの結果をArrayCollectionで簡単に受け取れるようrubyamf_config.rbを一部修正。ただしこの設定はRemoteObjectに対して有効で、NetConnectionではArrayCollectionが使えないため無効。
require 'app/configuration'
module RubyAMF
module Configuration
ClassMappings.assume_types = true
ClassMappings.use_array_collection = true
end
end
Flex側 (HTTPService – E4X)
load()とonResult()までの時間を10回測った。測定時間はTextAreaに、受信内容はDataGridにそれぞれ表示。
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HBox width="100%" height="100%">
<mx:DataGrid id="dg" width="50%" height="100%">
<mx:columns>
<mx:DataGridColumn dataField="id"/>
<mx:DataGridColumn dataField="name"/>
</mx:columns>
</mx:DataGrid>
<mx:TextArea id="loadText" width="50%" height="100%"/>
</mx:HBox>
<mx:Button label="Load" width="100" height="30" click="load(event)" />
<mx:Script>
<![CDATA[
import mx.rpc.http.HTTPService;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import flash.utils.getTimer;
private var _start:uint;
private var _str:String = "";
private function load(e:Event):void{
var req:HTTPService = new HTTPService();
req.url = "http://127.0.0.1:3000/users.xml";
req.resultFormat = HTTPService.RESULT_FORMAT_E4X;
req.send();
req.addEventListener(ResultEvent.RESULT,onResult);
req.addEventListener(FaultEvent.FAULT,onFault);
_start = getTimer();
}
private function onResult(e:ResultEvent):void{
dg.dataProvider = e.target.lastResult.user;
_str += (getTimer() - _start).toString() + " msec\n";
loadText.text = _str;
}
private function onFault(e:FaultEvent):void{
loadText.text = e.fault.faultDetail;
}
]]>
</mx:Script>
</mx:Application>
Flex側 (RemoteObject – AMF)
MXMLの骨格はHTTPServiceを使う場合と同じ。スクリプト部分とservices-config.xmlの設定は以下の通り。
スクリプト部分
<mx:Script>
<![CDATA[
import mx.rpc.remoting.RemoteObject;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import flash.utils.getTimer;
private var _start:uint;
private var _str:String = "";
private function load(e:Event):void{
var ro:RemoteObject = new RemoteObject();
ro.source = "UsersController";
ro.destination = "rubyamf";
ro.index();
ro.addEventListener(ResultEvent.RESULT,onResult);
ro.addEventListener(FaultEvent.FAULT,onFault);
_start = getTimer();
}
private function onResult(e:ResultEvent):void{
dg.dataProvider = e.result;
_str += (getTimer() - _start).toString() + " msec\n";
loadText.text = _str;
}
private function onFault(e:FaultEvent):void{
loadText.text = e.fault.faultString;
}
]]>
</mx:Script>
services-config.xml (コンパイラオプションに追加)
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="remoting-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="rubyamf">
<channels>
<channel ref="ch-rubyamf" />
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="ch-rubyamf"
class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://127.0.0.1:3000/rubyamf/gateway"
class="flex.messaging.endpoints.AMFEndpoint" />
</channel-definition>
</channels>
</services-config>
結果
HTTPService – E4X
load()からonResult()までの時間測定は右テキストエリア内(msec)。10回測定でだいたい0.5-0.6秒。ちなみにRESULT_FORMAT_OBJECT(ActionScript Object)で受信すると0.7-0.8秒ぐらいだった。

RemoteObject – AMF
HTTPServiceの場合と同じ測定で一回あたり約3秒。

AMF、通信設定が面倒なくせにすげー遅い。Ajax and Flex Data Loading Benchmarks | James Ward – RIA Cowboyの結果と違いすぎる。どっか間違ってる?
Read More