前田です。 At Wed, 28 May 2003 09:48:31 +0900, "NAKAMURA, Hiroshi" <nakahiro / sarion.co.jp> wrote: > 構造体を1000個やりとり! > > オブジェクトがでかいと、 > object <-A-> SOAP Data Model <-B-> XML instance > Integer SOAP::SOAPInt <foo xsi:type="xsd:int"/> > の、Aの部分も重そうですね。 はい、そうですね。 <complexType name="PostalData"> <all> <element name="jisCode" type="string" /> <element name="postCodeShort" type="string" /> <element name="postCode" type="string" /> <element name="prefKanji" type="string" /> <element name="cityKanji" type="string" /> <element name="townKanji" type="string" /> <element name="prefKana" type="string" /> <element name="cityKana" type="string" /> <element name="townKana" type="string" /> <element name="flag1" type="int" /> <element name="flag2" type="int" /> <element name="flag3" type="int" /> <element name="flag4" type="int" /> <element name="flag5" type="int" /> <element name="flag6" type="int" /> </all> </complexType> こんな感じの構造体300個の送信を計測してみると、 Ruby 1.6: RPCRouter#createResponse 2.434415 Processor.marshal 21.544701 Ruby 1.8: RPCRouter#createResponse 2.345288 Processor.marshal 2.905458 といった感じでした。 Ruby 1.6の場合、データ数が多くなると、String#+でやるよりString#<< の方が遅くなってしまうようです。 たぶん、大きなメモリを小刻みに何度もallocateするために遅くなってし まうのではないかと推測しています。 createResponseを def createResponse( namespace, methodName, result ) name = fqName( namespace, methodName ) if ( @method.has_key?( name )) method = @method[ name ] else raise RPCRoutingError.new( "Method: #{ name } not defined." ) end soapResponse = method.createMethodResponse soapReturnValue = SOAPReturnValue.new(result) # 自前のwrapper soapResponse.setRetVal(soapReturnValue) return soapResponse end のように再定義して、resultを一回ラップしてやるだけにしてから、 class String def soap_attr return ' xsi:type="xsd:string"' end def soap_content return to_s end end class Integer def soap_attr return ' xsi:type="xsd:int"' end def soap_content return to_s end end class PostalData def soap_attr return ' xsi:type="txsd:PostalData"' end def soap_content return <<EOF <jisCode xsi:type="xsd:string">#{@jisCode.soap_content}</jisCode> <postCodeShort xsi:type="xsd:string">#{@postCodeShort.soap_content}</postCodeShort> <postCode xsi:type="xsd:string">#{@postCode.soap_content}</postCode> <prefKanji xsi:type="xsd:string">#{@prefKanji.soap_content}</prefKanji> <cityKanji xsi:type="xsd:string">#{@cityKanji.soap_content}</cityKanji> <townKanji xsi:type="xsd:string">#{@townKanji.soap_content}</townKanji> <prefKana xsi:type="xsd:string">#{@prefKana.soap_content}</prefKana> <cityKana xsi:type="xsd:string">#{@cityKana.soap_content}</cityKana> <townKana xsi:type="xsd:string">#{@townKana.soap_content}</townKana> <flag1 xsi:type="xsd:int">#{@flag1.soap_content}</flag1> <flag2 xsi:type="xsd:int">#{@flag2.soap_content}</flag2> <flag3 xsi:type="xsd:int">#{@flag3.soap_content}</flag3> <flag4 xsi:type="xsd:int">#{@flag4.soap_content}</flag4> <flag5 xsi:type="xsd:int">#{@flag5.soap_content}</flag5> <flag6 xsi:type="xsd:int">#{@flag6.soap_content}</flag6> EOF end end のような要領でXMLを生成するようにすると、 Ruby 1.6: RPCRouter#createResponse 0.000607 Processor.marshal 0.129808 Ruby 1.8: RPCRouter#createResponse 0.000581 Processor.marshal 0.092752 と、劇的に早くなりました:) YAMLで書いたデータ定義からWSDLとテストケースを生成するようにして いるので、上記のようなコードも自動生成するようにしようと思ってい ます。 # 最初はWSDLを手で書いてたのですが、破綻しました:( > Stringの連結によるXML instance生成が遅いのであれば、 > IOに直接書くというのはどうですかね? 設定だけで、というわけには > いかないような気がしますが、なんかちょっと書いてみます。 > 別に使っていただかなくても、単になひの趣味で作るので > 気にしないでください。 おお、いいですね:) > ちなみにIOに書くときの問題は、途中で送るべきデータにエラーを発見 > しても、既に送ってしまっていて手遅れなこと。dRubyも同じ問題を > 抱えていた気がする(速度のためには直接IOに書きたいけど、 > 上記の問題で一度Stringにせざるを得ない)。 mod_rubyも同じ問題をかかえているのですが、結局設定で変えられるよ うにしてユーザに選択してもらうことにしました。 > > # 単純なデータのやり取りだけなので、SOAP4Rみたいにまじめにやらず > > # に、ほとんど決め打ちですませるつもりです(^_^; > > それで済むのがSOAPやXML-RPCのお気楽なところですね。 > Java搭載携帯端末でやってます。 はい、いじるのがラクでいいですね。 今回はクライアントがWindowsなのでSOAPを選択した(クライアント側は お客さんが作るので、なるべく労力が少なくてすむようにする必要があ るのです)のですが、WSDL4Rのおかげでコードを自動生成できるので重宝 しています:-) ほんとはRubyのソースからWSDLを自動生成したいところですが、コメン トに型情報を埋め込むとかしない無理ですよねえ。 -- 前田 修吾