3

double型の多くのメンバーを含む一連のstructインスタンスを格納するプログラムがあります。時々私はこれらをファイルにダンプします、それは私が文字列ビルダーを使ってやっていた例です:

 StringBuilder builder = new StringBuilder(256);

 builder.AppendFormat("{0};{1};{2};", x.A.ToString(), x.B.ToString(), x.C.ToString()); 

ここで、「x」は私のタイプのインスタンスであり、A、B、CはタイプdoubleのXのメンバーです。ボクシングを避けるために、これらのそれぞれでToString()を呼び出します。ただし、これらのToStringの呼び出しは、アプリケーションのコンテキストでまだ多くのメモリを割り当てているため、これを減らしたいと思います。私が考えているのは、文字配列を作成し、各メンバーをその配列に直接書き込んでから、その文字配列から1つの文字列を作成し、それをファイルにダンプすることです。いくつかの質問:

1)私が考えていることは合理的に聞こえますか?誰かがすでに似たようなことを達成することを知っているものはありますか?

2)doubleを文字配列に変換するための何かがすでに組み込まれていますか(これは、ある程度のパラメータ化された精度までだと思いますか?)。理想的には、配列といくつかのインデックスを渡して、そこに書き込みを開始させたいと考えています。

私がこれを行おうとしている理由は、多くのインスタンスを実行していて、メモリによって制限されていることが多いため、アプリの実行中にメモリの大きなスパイクを減らすためです。

乾杯A

4

5 に答える 5

3

ファイルは何らかのテキスト形式である必要がありますか?

そうでない場合、これを行う最も効率的な方法は、BinaryWriter (および BinaryReader を使用して読み戻す) を使用することです。

詳細については、 http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspxを参照してください。

于 2012-06-06T12:29:39.080 に答える
2

テキスト ファイルに直接書き込むことができる場合は、steamwriter を使用して、厳密に型指定された構造体を書き込むことができます。メモリ使用量はテストしていませんが、効率的であると思います

        using (var tw = new System.IO.StreamWriter("filename", true)) //(true to append to file)
        {
            tw.Write(x.A);
            tw.Write(';');
        }

stringbuilder が必要な場合は、次を使用して厳密に型指定されたオーバーロードを呼び出すこともできます。

        builder.Append(x.A) //strongly typed as long as the field is a system type
            .Append(';')
            .Append(x.B)
            .Append(';'); 

もちろん、どちらの方法もある種のループまたはデリゲートを実装する方が適切に見えますが、それはボクシング ロジックのそばにあります。

他の回答に投稿されたカスタム二重書き込みの編集: c# double から文字配列または代替

于 2012-06-06T12:56:22.823 に答える
1

どうすればいいのかという好奇心から、doublesを直接書くシナリオを作成しようとすることに抵抗できませんでした。結果は以下のとおりです。私はそれなどのベンチマークを行っていませんが、実行した(限定された)テストでは期待どおりに機能しました。

        double[] test = { 8.99999999, -4, 34.567, -234.2354, 2.34, 500.8 };
        using (var sw = new FileStream(@"c:\temp\test.txt", FileMode.Create))
        {
            using (var bw = new BinaryWriter(sw))
            {
                const byte semicol = 59, minus = 45, dec = 46, b0 = 48;

                Action<double> write = d =>
                {
                    if (d == 0)
                        bw.Write(b0);
                    else
                    {
                        if (d < 0)
                        {
                            bw.Write(minus);
                            d = -d;
                        }

                        double m = Math.Pow(10d, Math.Truncate(Math.Log10(d)));
                        while(true)
                        {
                            var r = ((decimal)(d / m) % 10); //decimal because of floating point errors
                            if (r == 0) break;
                            if (m == 0.1)
                                bw.Write(dec); //decimal point
                            bw.Write((byte)(48 + r));         
                            m /= 10d;
                        }
                    }

                    bw.Write(semicol);
                };

                foreach (var d in test)
                    write(d);
            }
        }
于 2012-06-06T20:02:06.297 に答える
1

Double.ToStringメモリの問題を引き起こしているのは、おそらく多くの呼び出しであると確信していますか? 各文字列は次世代 0 コレクションで収集する必要があり、.NET ガベージ コレクターはこれを行うのに非常に効率的です。

作成する文字列が 85K を超える場合、大きなオブジェクト ヒープ上に作成されるため、大きな文字列が一時的にしか存在しない場合でも (大きなオブジェクト ヒープの断片化)、アプリケーションに必要な合計メモリが増加する可能性があります。

パフォーマンス モニターを使用すると、アプリケーションがマネージ ヒープをどのように使用しているかを詳しく知ることができます。さらに高度なツールである CLRProfiler を使用しているため、新しいことは何も学べないかもしれません。

StringBuilderメモリ内に文字列を構築するための適切なクラスですが、メモリ内に文字列を構築して後でファイルに書き込むだけの場合は、代わりにStreamWriter.

StringBuilder文字列を格納するために使用されるバッファーを拡張する必要がありStringBuilder、事前に の容量を設定することで、この余分なオーバーヘッドを回避できます (サンプル コードで既にこれを行っています)。

Doubleaを aにフォーマットするために呼び出すオーバーロードに関係なく、StringBuilder最終的にDouble.ToStringは呼び出されます。StringBuilder.AppendFormat追加のフォーマットされた文字列を割り当てずにバッファに直接フォーマットするため、メモリ使用量の点でStringBuilder.AppendFormatは問題なくStringBuilder.Append、両方のオーバーロードがDoubleフォーマット プロセスの一部としてフォーマットされた文字列を割り当てます。ただし、配列を受け入れるため、StringBuilder.AppendFormatをボックス化します。を受け入れるオーバーロードを使用しても、この問題は発生しません。Doubleparams Object[]StringBuilder.AppendDouble

それがメモリの問題の原因であることが確実にわかっている場合Double.ToStringは、浮動小数点数を直接StringBuilder. この作業は簡単ではありませんが、オープン ソースの C ライブラリからインスピレーションを得ることができます。

于 2012-06-06T14:12:38.367 に答える