Xerces-C++でXMLからDOMツリー作ったりしてるんだけれど
最近パフォーマンス気にするようなコード書いてなかったので、非常に基礎的なところでハマってた。
テスト用の短いXMLだと問題なかったんだけど、本番用のXML食わせたらforの中では大したことやってないのに5分以上かかっちゃうわけ。
問題のコード
//... DOMNodeList* nodelist = document->getElementsByTagName(tagname); //... for(int i=0;i< nodelist->getLength();i++){ //.... }
ここだけ抜き出せばもうわかると思うけど、forの終了条件の中で nodelist->getLength() してる。こいつの計算コストがけっこう高い。
nodelist->getLength()をnodelist->getLength()回呼び出したらそりゃ遅い。
変数の名前考えるのが苦手なので、できるだけ変数宣言しないように書いてたらこうなったってのもある。
次のように書き直すべき
//... DOMNodeList* nodelist = document->getElementsByTagName(tagname); //... for(int i=0,num=nodelist->getLength();i<num;i++){ //.... }
今回作ってたケースでは、途中でリストのサイズが変わったりしないので最初に1回計算すればそれでよかったわけ。
だからforの初期条件のところで、あらかじめ計算するようにしたよ。
これだけで5分以上かかってたコードが1秒ちょっとで終わったよ。
ちなみに、Xercec-c++(2.8.0)のsrc/xercesc/dom/impl/DOMNodeListImpl.cppには、ご丁寧に
// this implementation is too stupid – needs a cache of some kind.
って書いてあるよ。