htmlで, 色々値を入れたtableを書くことになったとき, 次のようなコードを書きました.
string getHtmlCode(IQueryable<Post> values) { string body = "<table>"; int counter = 1; foreach (var _value in values) { body += String.Format( "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>" , counter++ , _value.something1 , _value.something2 , _value.something3 ); } body += "</table>"; return body; }
そしたら, この場合, 単純な文字列連結ではなく, StringBuilder を使うといい, と, 教えてもらいました!
ということで StringBuilder を使って書き直しました!
string getHtmlCode(IQueryable<Post> values) { var tableBody = new System.Text.StringBuilder(); tableBody.Append("<table>"); int counter = 1; foreach (var _value in values) { tableBody.AppendFormat( "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>" , counter++ , _value.something1 , _value.something2 , _value.something3 ); } tableBody.Append("</table>"); return tableBody.ToString(); }
なぜ?
どうして, この場合(ガンガンループ回す中では)単純な文字連結よりもStringBuilder使ったほうがいいのかも聞きました.
string型は,
連続したメモリ領域を食います.
それで, 文字長がどんどん長くなっていったら,
今までいた場所の(連続した場所)残りが足りなくなったら, いったんそこを開放して, 別のもっと余裕のあるところにメモリを取ります.
それでもまた足りなくなったらまた開放して, 別の広いところにメモリを取って自身を書き込みます.
そうやって開放と取るのを繰り返すのは, とても重いことらしいです.
たぶん, 新婚さんが2人暮らしのマンションに住んでて,
ひとり子供が生まれたので3人暮らしの広さのマンションに引っ越して, (引越代とか色々コストがかかる)
さらにもうひとり二人目の子供が生まれたので4人暮らしのマンションに引っ越して,
みたいのを延々とやることになるからマズイのかなって思いました.
(((o( *゚▽゚* )o)))
いっぽう, StringBuilderのほうは,
あとで足すのをいったん別の場所に(.Append()で)それぞれ置いておいて,
最後に一気に連結します.
だから, メモリ解放と取るのを繰り返すことが無いので, しあわせなようです.
[追記] 私の記憶違いらしく, 違うらしい! コメントで教えていただきました! ありがとうございます!
http://msdn.microsoft.com/ja-jp/library/system.text.stringbuilder(v=vs.110).aspx
機械翻訳みたいなので日本語がおかしいけど、最後に連結するわけではなくて多めにバッファーを取って溢れたらバッファーを増やすって言うのを繰り返すみたいですよ。
間違ってもいいからブログでアウトプット出すのはとても尊いので見習いたいです。
あわわわ, そうだったんだ, ありがとうございます, ありがとうございます!
Append時の部分文字列のポインタだけ持っておいて最後に一気に結合の方が速いけどそういう実装見たことないなあ、と思って考えてみましたが、部分文字列のままだとIndexOfとかReplaceとか実装するのに効率悪くなりそうです。Dictionaryもcapacity持って足りなくなったら拡張するタイプですね。
http://msdn.microsoft.com/en-us/library/tk84bxf4(v=vs.110).aspx
Javaの公式ドキュメントだとちゃんとした日本語で説明されています。loadFactor(負荷係数)を使ったcapacity拡張の説明もあってわかりやすいですよ(Javaを勧めているわけではない
http://docs.oracle.com/javase/jp/6/api/java/util/HashMap.html