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の結果と違いすぎる。どっか間違ってる?