khi*_*kle 4 c# optimization performance
我正在开发一个应用程序,它从大量文本文件(~2.5 GB)读取行,将每行操作为特定格式,然后将每行写入文本文件.一旦输出文本文件关闭,程序"批量插入"(SQL Server)将数据存入我的数据库.它有效,它只是很慢.
我正在使用StreamReader和StreamWriter.
由于我必须操纵文本,我几乎一直在阅读一行.但是,我认为,如果我制作了一系列线条并且每1000行左右写出一个集合,那么它至少可以加快速度.问题是(这可能纯粹是出于我的无知),我不能写一个string[]使用StreamWriter.在探索StackOverflow和互联网的其余部分后,我遇到了File.WriteAllLines,它允许我写入string[]文件,但我不认为我的计算机的内存可以处理2.5 GB的数据一次存储.此外,文件已创建,填充和关闭,因此我必须制作大量较小的文件来分解2 GB文本文件,只是将它们插入数据库.所以我宁愿远离这个选择.
我能想到的一个黑客工作是制作一个StringBuilder并使用该AppendLine方法添加每一行来制作一个巨大的字符串.然后我可以将其转换StringBuilder为字符串并将其写入文件.
但足够我的推测.我已经实现的方法有效,但我想知道是否有人可以建议更好的方法将数据块写入文件?
Jim*_*hel 11
两件事会增加使用的输出速度StreamWriter.
首先,确保输出文件与输入文件位于不同的物理磁盘上.如果输入和输出在同一个驱动器上,那么读取通常必须等待写入和写入必须等待读取.磁盘一次只能做一件事.显然不是每次读取或写入都会等待,因为StreamReader读取缓冲区并从中解析出行,并StreamWriter写入缓冲区,然后在缓冲区满时将其推送到磁盘.将输入和输出文件放在不同的驱动器上,您的读写重叠.
他是什么意思重叠?操作系统通常会提前读取,因此它可以在您处理时缓冲文件.当你进行写操作时,操作系统通常会缓冲它并将其懒惰地写入磁盘.因此,正在进行一些有限的异步处理.
第二件事是增加缓冲区大小.为默认的缓冲区大小StreamReader和StreamWriter为4千字节.因此,每次读取或写入4K都会产生操作系统调用.并且,很可能是磁盘操作.
如果将缓冲区大小增加到64K,则操作系统调用次数减少16次,磁盘操作次数减少16次(严格来说不是这样,但是关闭).使用64K缓冲区可以减少超过25%的I/O时间,这很简单:
const int BufferSize = 64 * 1024;
var reader = new StreamReader(filename, Encoding.UTF8, true, BufferSize);
var writer = new StreamWriter(filename, Encoding.UTF8, BufferSize);
Run Code Online (Sandbox Code Playgroud)
这两件事将比你能做的任何其他事情都更快地加速你的I/O. 尝试在内存中使用缓冲区构建StringBuilder只是不必要的工作,通过增加缓冲区大小来复制可以实现的功能,并且错误地完成可能会使程序变得更慢.
我会提醒大小超过64 KB的缓冲区大小.在某些系统上,缓冲区高达256 KB会获得稍微好一些的结果,但在其他系统上,性能会大大降低 - 速度会慢50%!我从未见过使用大于256 KB的缓冲区比使用64 KB缓冲区更好的系统.根据我的经验,64 KB是最佳选择.
您可以做的另一件事是使用三个线程:阅读器,处理器和编写器.他们与队列进行通信.这可以减少你的总时间(input-time + process-time + output-time)到非常接近的时间max(input-time, process-time, output-time).使用.NET,设置起来非常简单.请参阅我的博客文章:简单多线程,第1部分和简单多线程,第2部分.
根据文档,StreamWriter默认情况下每次写入后都不会自动刷新,因此它是缓冲的.
你也可以在File类上使用一些惰性方法,如下所示:
File.WriteAllLines("output.txt",
File.ReadLines("filename.txt").Select(ProcessLine));
Run Code Online (Sandbox Code Playgroud)
在哪里ProcessLine声明如下:
private string ProcessLine(string input) {
string result = // do some calculation on input
return result;
}
Run Code Online (Sandbox Code Playgroud)
由于ReadLines是懒惰的并且WriteAllLines具有延迟重载,因此它将流式传输文件而不是尝试读取整个文件.