C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: StringBuilderでの文字連結の速度について


(過去ログ 136 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■79955 / inTopicNo.1)  StringBuilderでの文字連結の速度について
  
□投稿者/ つまようじ (1回)-(2016/06/01(Wed) 11:27:34)

分類:[C#] 

2016/06/01(Wed) 11:33:41 編集(投稿者)
2016/06/01(Wed) 11:33:29 編集(投稿者)

<pre><pre>こんにちは
初めて質問させていただきます。

現在、VB2010 .net framework 3.0 C#にてCSV出力プログラムを作成しています。
StringBuilderで文字連結を行っていると定期的に時間がかかってしまう行があります。


以下ソース

StringBuilder sb = new StringBuilder(1024 * 10000);
int[] t1 = new int[3000];

for (int count = 0; count < 3000; count++)
{
	//開始時間測定
	t1[count] = System.Environment.TickCount;

	for(int count2 = 0; count2 < 3000; count2++)
	{	
		//文字連結
		sb.Append("1.0000000000E+60").Append(",");
	}
	//改行
	sb.Append("\n");
	
	//終了時間測定
	t1[count] = System.Environment.TickCount - t1[count];
}

だいたい100行に一回程度10ms程度かかる行があり、
原因がわからず、困っております。 

皆さま、ご教授よろしくお願いいたします。</pre></pre>

引用返信 編集キー/
■79960 / inTopicNo.2)  Re[1]: StringBuilderでの文字連結の速度について
□投稿者/ とっちゃん (366回)-(2016/06/01(Wed) 11:59:57)
No79955 (つまようじ さん) に返信

> 現在、VB2010 .net framework 3.0 C#にてCSV出力プログラムを作成しています。
> StringBuilderで文字連結を行っていると定期的に時間がかかってしまう行があります。
>
>
> 以下ソース
>
> StringBuilder sb = new StringBuilder(1024 * 10000);
> int[] t1 = new int[3000];
>
> for (int count = 0; count < 3000; count++)
> {
> //開始時間測定
> t1[count] = System.Environment.TickCount;
>
> for(int count2 = 0; count2 < 3000; count2++)
> {
> //文字連結
> sb.Append("1.0000000000E+60").Append(",");
> }
> //改行
> sb.Append("\n");
>
> //終了時間測定
> t1[count] = System.Environment.TickCount - t1[count];
> }
>
> だいたい100行に一回程度10ms程度かかる行があり、
> 原因がわからず、困っております。
>
> 皆さま、ご教授よろしくお願いいたします。

1行あたりの文字数が

"1.0000000000E+60"+","の1文字で18文字あります。これを3000回つなげるので
18x3000 で 54,000文字。
これが1行あたりの文字数になります(正確には、これに改行が入るのですがそこは省略)。
一方、StringBuilder に渡した初期のキャパシティは、1024x10,000 なので、10,240,000 文字分。
ざっくりですが200行には足らない程度の量となります。


時間のかかるタイミングですが、最初の200行くらいは問題がなく
そのあと100行いかないくらいの間隔で時間がかかっていませんか?

自分では計測していないのでわかりませんが。
もしそうなら、想定される動作の範疇にあると言えます。


このデータの場合、必要となるメモリサイズは、
(18x3000+1)*3000 文字分なので、162,003,000 文字分になります。
少し余裕を持たせるなら、60000*3000あればよいと思います。

もし、これでも途中で時間がかかるタイミングがある場合は、文字数と言いながらバイト数を確保していると思うので
さらにx2すれば、時間がかかることはないと思います。

ただ、そこまでするくらいなら、直接ストリームに書き込むほうが良いと思いますけどね。

引用返信 編集キー/
■79962 / inTopicNo.3)  Re[2]: StringBuilderでの文字連結の速度について
□投稿者/ つまようじ (2回)-(2016/06/01(Wed) 13:10:13)
No79960 (とっちゃん さん) に返信
早速の返信ありがとうございます。

>時間のかかるタイミングですが、最初の200行くらいは問題がなく
>そのあと100行いかないくらいの間隔で時間がかかっていませんか?

指摘された通り200行ちょっとで時間がかかっていました。
StringBuilderのキャパシティを増やしてみたところ、逆に遅くなる頻度が増えてしまいました。
(メモリが足りてない?)

もうちょっと試行錯誤してみようと思います。
有難うございました。


引用返信 編集キー/
■79963 / inTopicNo.4)  Re[3]: StringBuilderでの文字連結の速度について
□投稿者/ とっちゃん (367回)-(2016/06/01(Wed) 13:18:06)
No79962 (つまようじ さん) に返信
> >時間のかかるタイミングですが、最初の200行くらいは問題がなく
> >そのあと100行いかないくらいの間隔で時間がかかっていませんか?
>
> 指摘された通り200行ちょっとで時間がかかっていました。
> StringBuilderのキャパシティを増やしてみたところ、逆に遅くなる頻度が増えてしまいました。
> (メモリが足りてない?)
>
キャパシティはいくつまで増やしてみました?
生成される文字列よりも大きな数まで増やしてみましたか?

それでどう変わるかわかりませんが、状況によってはストリームへの直接出力を
考えたほうがいいと思います。

引用返信 編集キー/
■79967 / inTopicNo.5)  Re[4]: StringBuilderでの文字連結の速度について
□投稿者/ なちゃ (114回)-(2016/06/01(Wed) 15:24:45)
とっちゃんさんが何度か書かれてますが、ストリームに直接書き出すことをおすすめします。
今のやり方だと、メモリの連続領域で350MBくらい喰うことになりますし、美妙にサイズ変わったりして下手をすれば、最悪倍になる可能性があります。
700MBの連続領域は、32ビットアプリだと高い確率で確保に失敗します。
半分でも結構やばいですが。

またちなみに、この挙動は.NET Framework 4以降では変わります。
連続領域ではなく、チャンク分割されたバッファを使うようになるため、定期的な動作の遅延は発生しません。
ただし、最後にTpStringで文字列化する際に連続領域が必要になりますし、その瞬間は倍のメモリを使用しますから、これまた結構な確率で確保に失敗する可能性があります。

総じてお勧めできないということになります。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -