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

我整理了一个我认为更简洁的简单片段;但是,话又说回来,我不太确定你想要完成什么。另外,我没有你的任何课程,所以我真的不能做任何类型的测试。

该示例与您所做的基本相同;除了它使用了一些通用方法,而且它在一个地方完成了所有的写作。

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 回答