我正在开发一个C#程序,它读取非常大的文件并检查它们是否有不同的属性和字段。我一直在测试不到100万行的文件,并按预期进行预编译。我最近在一个包含250万行的文件上进行了测试,花了4个小时才完成。
我使用自定义阅读功能读取每个字符,以便我可以找到所有CR和LF,因为每行包含它们非常重要。我已经单独测试了阅读功能,它看起来大约需要14分钟来读取文件,我觉得这个文件足够合理,可以读取250个行中1500个字符的每个字符。我将把阅读功能包括在内,但这似乎不会导致问题。
我的阅读功能将每个字符添加到字符串中,然后检查字符串中的不同值。例如,行长度是否正确,文件是否包含标题,标题是否包含正确的值。以及特定值如char位置403-404一个数字,是字段1250-1300不为空等等。
我的问题是我该怎么做才能找出导致速度减慢的原因并提高我的程序效率?我已经尝试检查每个循环开始和结束时的时间,但似乎没有改变。但是,每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;
}
}
答案 0 :(得分:11)
这是我寻找的第一件事,也是我要改变的第一件事:
currentLine += char.ConvertFromUtf32(asciiValue);
不要那样做。在循环中使用字符串连接可以 kill 性能 - 您获得O(N 2 )复杂性。请改用StringBuilder
。有关详细说明,请参阅my article on when to use StringBuilder
。
您可以做的更多,但只是更改为使用StringBuilder
将是巨大的改进:
StringBuilder builder = new StringBuilder();
while (...)
{
...
builder.Append(char.ConvertFromUtf32(asciiValue));
}
currentLine = builder.ToString();
还不清楚为什么你有这么多的参数。你为什么要过asciiValue
?你为什么通过引用传递StreamReader
?使用这么多ref参数的任何东西都会让我非常紧张 - 为什么你没有一个类型来封装你想要从方法中返回的所有内容?
您可能需要阅读我的article on parameter passing以更好地了解ref
。