7

私は次のように何かを始めました:

using (TextWriter textWriter = new StreamWriter(filePath, append))
{
    foreach (MyClassA myClassA in myClassAs)
    {
        textWriter.WriteLine(myIO.GetCharArray(myClassA));

        if (myClassA.MyClassBs != null)
            myClassA.MyClassBs.ToList()
                .ForEach(myClassB =>
                    textWriter.WriteLine(myIO.GetCharArray((myClassB)));

        if (myClassA.MyClassCs != null)
            myClassA.MyClassCs.ToList()
                .ForEach(myClassC =>
                    textWriter.WriteLine(myIO.GetCharArray(myClassC)));
    }
}

これはかなり遅いように見えました (35,000 行で約 35 秒)。

次に、こちらの例に従って、次のコードでバッファを作成しようとしましたが、何も得られませんでした。私はまだ35秒前後の時間を見ていた. バッファの実装方法に誤りがありますか?

using (TextWriter textWriter = new StreamWriter(filePath, append))
{
    char[] newLineChars = Environment.NewLine.ToCharArray();
    //Chunk through 10 lines at a time.
    int bufferSize = 500 * (RECORD_SIZE + newLineChars.Count());
    char[] buffer = new char[bufferSize];
    int recordLineSize = RECORD_SIZE + newLineChars.Count();
    int bufferIndex = 0;

    foreach (MyClassA myClassA in myClassAs)
    {
        IEnumerable<IMyClass> myClasses =
            new List<IMyClass> { myClassA }
                .Union(myClassA.MyClassBs)
                .Union(myClassA.MyClassCs);

        foreach (IMyClass myClass in myClasses)
        {
            Array.Copy(myIO.GetCharArray(myClass).Concat(newLineChars).ToArray(),
                0, buffer, bufferIndex, recordLineSize);

            bufferIndex += recordLineSize;

            if (bufferIndex >= bufferSize)
            {
                textWriter.Write(buffer);

                bufferIndex = 0;
            }
        }
    }

    if (bufferIndex > 0)
        textWriter.Write(buffer);
}

これを達成するためのより良い方法はありますか?

4

3 に答える 3

9

あなたの時間の大部分は I/O に費やされていないのではないかと強く思います。本当に長い行でない限り、35,000 行を書き込むのに 35 秒かかるはずはありません。

GetCharArrayほとんどの場合、それが何をするにしても、大部分の時間はメソッドに費やされます。

いくつかの提案:

本当に I/O に問題があると思われる場合は、ストリームのバッファ サイズを増やしてください。バッファー サイズを指定できるStreamWriter コンストラクターを呼び出します。例えば、

using (TextWriter textWriter = new StreamWriter(filePath, append, Encoding.Utf8, 65536))

これは、デフォルトの 4K バッファ サイズよりも優れたパフォーマンスを発揮します。バッファー サイズを 64K より大きくすることは一般的には役に立たず、実際にはパフォーマンスが低下する可能性があります。

行を事前にバッファリングしたり、に追加したりしないでくださいStringBuilder。これにより、パフォーマンスがわずかに向上する可能性がありますが、複雑さが大幅に低下します。わずかなパフォーマンスの向上は、メンテナンスの悪夢に値しません。

を活用してくださいforeach。あなたはこのコードを持っています:

if (myClassA.MyClassBs != null)
    myClassA.MyClassBs.ToList()
        .ForEach(myClassB =>
            textWriter.WriteLine(myIO.GetCharArray((myClassB)));

MyClassBsコレクションが何であれ、具体的なリストを作成し、それを列挙する必要があります。ものを直接列挙しないのはなぜですか:

if (myClassA.MyClassBs != null)
{
    foreach (var myClassB in myClassA.MyClassBs)
    {
        textWriter.WriteLine(myIO.GetCharArray((myClassB)));
    }
}

ToListこれにより、 に必要なメモリと、リストを作成するときにコレクションを列挙するのにかかる時間を節約できます。

そうは言っても、あなたのGetCharArray方法が常に時間を取っていることはほぼ確実です。本当にプログラムを高速化したい場合は、そこを見てください。への書き込みを最適化しようとするのStreamWriterは時間の無駄です。そこでは、パフォーマンスが大幅に向上することはありません。

于 2013-06-26T22:02:57.417 に答える
1

少しすっきりしたと思う簡単なスニペットをまとめました。しかし、繰り返しますが、あなたが何を達成しようとしているのかよくわかりません。また、私はあなたのクラスを利用できないので、実際にどのような種類のテストも行うことができません.

このサンプルは基本的に同じことを行います。ただし、いくつかの一般的な方法を使用し、すべての書き込みを 1 か所で行います。

string filePath = "MickeyMouse.txt";
bool append = false;
List<MyClassA> myClassAs = new List<MyClassA> { new MyClassA() };
    List<char[]> outputLines = new List<char[]>();

foreach (MyClassA myClassA in myClassAs)
{
    outputLines.Add(myIO.GetCharArray(myClassA));

    if (myClassA.MyClassBs != null)
        outputLines.AddRange(myClassA.MyClassBs.Select(myClassB => myIO.GetCharArray(myClassB)));

    if (myClassA.MyClassCs != null)
        outputLines.AddRange(myClassA.MyClassCs.Select(myClassC => myIO.GetCharArray(myClassC)));
}

var lines = outputLines.Select(line => string.Concat<char>(line));
if (append)
    File.AppendAllLines(filePath, lines);
else
    File.WriteAllLines(filePath, lines);

StringBuilder のバージョンは次のとおりです。

string filePath = "MickeyMouse.txt";
bool append = false;
List<MyClassA> myClassAs = new List<MyClassA> { new MyClassA() };
StringBuilder outputLines = new StringBuilder();

foreach (MyClassA myClassA in myClassAs)
{
    outputLines.Append(myIO.GetCharArray(myClassA));

    if (myClassA.MyClassBs != null)
        myClassA.MyClassBs.ForEach(myClassB=>outputLines.Append(myClassB));

    if (myClassA.MyClassCs != null)
        myClassA.MyClassCs.ForEach(myClassC => outputLines.Append(myClassC));
}

if (append)
    File.AppendAllText(filePath, outputLines.ToString());
else
    File.WriteAllText(filePath, outputLines.ToString());
于 2013-06-26T18:52:34.407 に答える
0

書き込みにバッファリングされたストリームを使用する

たとえば、コンソールへのバッファリングされた書き込み用

TextWriter w = new StreamWriter(new BufferedStream(Console.OpenStandardOutput()));
    w.WriteLine("Your text here");

同様に、ファイルへのバッファリングされた書き込みの使用

TextWriter w = new StreamWriter(new BufferedStream(new FileStream("myFilePath.txt", FileMode.Create)));
w.WriteLine("Your text here");
于 2018-06-03T11:50:38.467 に答える