我有一个要处理的大文本文件列表。我想知道哪种方法最快,因为逐行阅读很慢。 我有类似的东西:
int cnt = this.listView1.Items.Count;
for (int i = 0; i < this.listView1.Items.Count; i++)
{
FileStream fs = new FileStream(this.listView1.Items[i].Text.ToString(), FileMode.Open, FileAccess.Read);
using (StreamReader reader = new StreamReader(fs))
while (reader.Peek() != -1)
{
//code part
}
}
我通过具有多个线程的后台工作者阅读有关使用块(每个100k行)的信息会有所帮助,但我不知道如何实现它。或者,如果您有更好的想法来改善绩效......我们将非常感谢您的专业建议。
答案 0 :(得分:4)
首先,您需要确定什么是瓶颈 - I / O(读取文件)或CPU(处理它们)。如果它是I / O,同时读取多个文件对你没什么帮助,你可以实现的最多就是有一个线程读取文件,另一个处理它们。处理线程将在下一个文件可用之前完成。
我同意@asawyer,如果它只有100MB,你应该一下子将文件完全读入内存。你不妨将其中的5个完全读入内存,这真的不是什么大问题。
编辑:确认所有文件都在一个硬盘驱动器上,并且处理所需的时间比读取文件的时间长。
你应该在线程上顺序读取文件。读取文件后,启动另一个处理处理的线程,并开始读取第一个线程中的第二个文件。读取第二个文件后,启动另一个线程,依此类推。
您应该确保不会激活比您拥有的核心数更多的处理线程,但是对于初学者来说,只需使用线程池,然后再进行优化。
您缺少一点性能,因为您花在阅读第一个文件上的时间不会用于任何处理。这应该是可以忽略不计的,将100MB的数据读取到内存中的时间不应超过几秒钟。
答案 1 :(得分:2)
我假设你是逐行处理文件。您还说加载文件比处理它们更快。您可以通过几种方式完成所需。例如:
创建一个逐行读取文件的线程。顺便说一句,因为当并行执行此操作时,您只会敲击硬盘并可能会导致更糟糕的结果。您可以使用Queue<string>
。使用Queue.Enqueue()
添加红色线条。
运行另一个正在处理队列的线程。使用Queue.Dequeue()
从队列的开头获取(和删除)行。处理该行并将其写入输出文件。最后,您可以将处理过的行放在另一个队列或列表中,并在完成处理后立即写入。
如果输出文件中的行顺序不重要,您可以创建与CPU核心(或使用ThreadPool
类)一样多的线程来进行处理(这会显着加快速度)。
[编辑] 如果输出文件中的行顺序很重要,则应将行处理限制为一个线程。或者使用单独的线程并行处理它们并实现控制输出顺序的机制。例如,您可以通过对从输入文件中读取的行(简单方法)编号,或者按照n行的块中的每个线程处理行,并按照开始处理线程的相同顺序按块写入输出块来执行此操作。
答案 2 :(得分:-1)
这是一个你可以使用的简单线程代码:(。Net 4)
//firstly get file paths from listview so you won't block the UI thread
List<string> filesPaths = new List<string>();
for (int i = 0; i < this.listView1.Items.Count; i++)
{
filesPaths.Add(listView1.Items[i].Text.ToString());
}
//this foreach loop will fire 50 threads at same time to read 50 files
Parallel.ForEach(filesPaths, new ParallelOptions() { MaxDegreeOfParallelism = 50 }, (filepath, i, j) =>
{
//read file contents
string data = File.ReadAllText(filepath);
//do whatever you want with the contents
});
虽未测试......