【问题标题】:C# Increasing Efficiency of a Program?C# 提高程序的效率?
【发布时间】:2011-09-09 14:13:23
【问题描述】:

我正在开发一个 C# 程序,该程序读取非常大的文件并检查它们的不同属性和字段。我一直在测试少于 100 万行的文件,它按预期进行。我最近在一个有 250 万行的文件上对其进行了测试,运行了 4 个小时。

我正在使用自定义阅读功能来读取每个字符,以便我可以找到所有 CR 和 LF,因为每一行都包含它们非常重要。我已经单独测试了 Reading 功能,读取文件大约需要 14 分钟,我认为这足以读取 250 万行 1500 个字符中的每个字符。我将包括阅读功能,但这似乎不会导致问题。

我的阅读函数将每个字符添加到一个字符串中,然后我检查字符串中的不同值。例如,行长度是否正确,文件是否包含标题,标题是否包含正确的值。以及特定值,例如 char 位置 403-404 是一个数字,字段 1250-1300 不是 null 等等。

我的问题是我可以做些什么来找出导致程序变慢的原因并提高我的程序效率?我试过检查每行循环开始和结束的时间,它似乎没有改变。但是,每 100,000 次所需的时间明显长于前一次。例如,处理线 10,000 到 20,000 用时不到 3 秒,而 830,000 到 840,000 用时大约 35 秒。我考虑过尝试使用多个线程,但不认为这对我从文件中读取行有帮助。想法?谢谢您的帮助!

    static void ReadMyLine(ref string currentLine, string filePath, ref int asciiValue, ref Boolean isMissingCR, ref Boolean isMissingLF, ref Boolean isReversed, ref StreamReader file)
    {
        Boolean endOfRow = false;
        isMissingCR = false;
        isMissingLF = false;
        isReversed = false;

        currentLine = "";

        while (endOfRow == false)
        {
            asciiValue = file.Read();

            if (asciiValue == 10 || asciiValue == 13)
            {
                int asciiValueTemp = file.Peek();

                if (asciiValue == 13 && asciiValueTemp == 10)
                {
                    endOfRow = true;
                    asciiValue = file.Read();
                }
                else if (asciiValue == 10 && asciiValueTemp == 13)   // CRLF Reversed
                {
                    asciiValue = file.Read();
                    endOfRow = true;
                    isReversed = true;
                }
                else if (asciiValue == 10)                           // Missing CR
                {
                    isMissingCR = true;
                    endOfRow = true;
                }
                else if (asciiValue == 13)                           // Missing LF
                {
                    isMissingLF = true;
                    endOfRow = true;
                }
                else
                    endOfRow = true;
            }
            else if (asciiValue != -1)
                currentLine += char.ConvertFromUtf32(asciiValue);
            else
                endOfRow = true;
        }
    }

【问题讨论】:

  • 我没有,有什么软件可以推荐的吗?
  • visual studio 已经进入了这个功能(至少在专业版中)

标签: c# visual-studio-2010 c#-4.0 file-io streamreader


【解决方案1】:

这是我寻找的第一件事,也是我要改变的第一件事:

currentLine += char.ConvertFromUtf32(asciiValue);

不要那样做。在循环中使用字符串连接可以杀死性能 - 你会得到 O(N2) 复杂度。请改用StringBuilder。更多解释见my article on when to use StringBuilder

您可能还可以做更多的事情,但只是改为使用StringBuilder 将是一个巨大的改进:

StringBuilder builder = new StringBuilder();
while (...)
{
    ...
    builder.Append(char.ConvertFromUtf32(asciiValue));
}
currentLine = builder.ToString();

不清楚为什么你有这么多 ref 参数。你为什么要传入asciiValue?你为什么要通过引用传递StreamReader?使用这么多 ref 参数的任何事情都让我非常紧张 - 为什么你没有一个类型来封装你真正想要从方法返回的所有内容?

您可能想阅读我的article on parameter passing 以更好地了解ref

【讨论】:

  • 我同意乔恩的观点。您连接的每个字符串实际上是该字符串在内存中重新创建并在堆上引用之前的副本 - 有很多这样的字符串肯定会影响应用程序性能。
  • @Jon 这种带有静态方法和所有这些 ref 参数的签名通常是由在方法中间选择一堆代码并使用 Visual Studio 的“提取方法”选项引起的。它不是很聪明。
  • @buzzzzjay:你永远不会改变file 的值,那为什么是ref?如果您只想要asciiValue out 的值,则应使用out 参数- 或返回值!有一个带有 ref 参数的 void 方法真的很难看。但看起来该方法确实想要返回几条信息:因此声明一个类型来封装该信息,并使其成为该方法的返回类型。
  • @buzzzzjay:这表明当涉及到 StreamReader 之类的引用类型时,您不了解 C# 中的参数传递是如何工作的。阅读第二个链接...
  • @buzzzzjay:是的 - 通过引用传递它。您只是传递 reference,而不是对象本身。调用者仍然可以看到由于读取对象而对对象所做的更改。我建议你再读一遍这篇文章,非常仔细——尤其是 StringBuilder 引用按值传递,然后附加“世界”的例子。
猜你喜欢
  • 2018-04-18
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
相关资源
最近更新 更多