我有 100000 行的大 txt 文件。我需要启动 n 个线程并从这个文件中为每个线程提供唯一的行。
做这个的最好方式是什么?我想我需要逐行读取文件,并且迭代器必须是全局的才能锁定它。将文本文件加载到列表中会很耗时,而且我会收到OutofMemory
异常。有任何想法吗?
我有 100000 行的大 txt 文件。我需要启动 n 个线程并从这个文件中为每个线程提供唯一的行。
做这个的最好方式是什么?我想我需要逐行读取文件,并且迭代器必须是全局的才能锁定它。将文本文件加载到列表中会很耗时,而且我会收到OutofMemory
异常。有任何想法吗?
您可以使用File.ReadLines 方法逐行读取文件,而无需一次将整个文件加载到内存中,并使用Parallel.ForEach 方法在多个线程中并行处理行:
Parallel.ForEach(File.ReadLines("file.txt"), (line, _, lineNumber) =>
{
// your code here
});
在执行我自己的基准测试以将 61,277,203 行加载到内存中并将值推入 Dictionary / ConcurrentDictionary() 之后,结果似乎支持@dtb 上面的回答,即使用以下方法是最快的:
Parallel.ForEach(File.ReadLines(catalogPath), line =>
{
});
我的测试还显示了以下内容:
我已包含此模式的示例以供参考,因为它不包含在此页面中:
var inputLines = new BlockingCollection<string>();
ConcurrentDictionary<int, int> catalog = new ConcurrentDictionary<int, int>();
var readLines = Task.Factory.StartNew(() =>
{
foreach (var line in File.ReadLines(catalogPath))
inputLines.Add(line);
inputLines.CompleteAdding();
});
var processLines = Task.Factory.StartNew(() =>
{
Parallel.ForEach(inputLines.GetConsumingEnumerable(), line =>
{
string[] lineFields = line.Split('\t');
int genomicId = int.Parse(lineFields[3]);
int taxId = int.Parse(lineFields[0]);
catalog.TryAdd(genomicId, taxId);
});
});
Task.WaitAll(readLines, processLines);
这是我的基准:
我怀疑在某些处理条件下,生产者/消费者模式可能优于简单的 Parallel.ForEach(File.ReadLines()) 模式。但是,它没有在这种情况下。
就像是:
public class ParallelReadExample
{
public static IEnumerable LineGenerator(StreamReader sr)
{
while ((line = sr.ReadLine()) != null)
{
yield return line;
}
}
static void Main()
{
// Display powers of 2 up to the exponent 8:
StreamReader sr = new StreamReader("yourfile.txt")
Parallel.ForEach(LineGenerator(sr), currentLine =>
{
// Do your thing with currentLine here...
} //close lambda expression
);
sr.Close();
}
}
认为它会工作。(这里没有 C# 编译器/IDE)
如果要将线程数限制为n
,最简单的方法是使用AsParallel()
withWithDegreeOfParallelism(n)
来限制线程数:
string filename = "C:\\TEST\\TEST.DATA";
int n = 5;
foreach (var line in File.ReadLines(filename).AsParallel().WithDegreeOfParallelism(n))
{
// Process line.
}
As @dtb mentioned above, the fastest way to read a file and then process the individual lines in a file is to: 1) do a File.ReadAllLines() into an array 2) Use a Parallel.For loop to iterate over the array.
You can read more performance benchmarks here.
The basic gist of the code you would have to write is:
string[] AllLines = File.ReadAllLines(fileName);
Parallel.For(0, AllLines.Length, x =>
{
DoStuff(AllLines[x]);
//whatever you need to do
});
With the introduction of bigger array sizes in .Net4, as long as you have plenty of memory, this shouldn't be an issue.