Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多线程读取大型txt文件?_C# - Fatal编程技术网

C# 多线程读取大型txt文件?

C# 多线程读取大型txt文件?,c#,C#,我有10万行的大txt文件。 我需要开始n个线程的计数,并从这个文件中为每个线程指定唯一的行 最好的方法是什么?我想我需要逐行读取文件,迭代器必须是全局的才能锁定它。将文本文件加载到列表将非常耗时,我可以收到OutofMemory异常。有什么想法吗?在一个线程上读取文件,将其行添加到一个线程中。启动从该队列读取的N任务。设置队列以防止内存不足错误。您可以使用逐行读取文件,而无需立即将整个文件加载到内存中,也可以使用并行处理多个线程中的行: Parallel.ForEach(File.ReadLi

我有10万行的大txt文件。 我需要开始n个线程的计数,并从这个文件中为每个线程指定唯一的行


最好的方法是什么?我想我需要逐行读取文件,迭代器必须是全局的才能锁定它。将文本文件加载到列表将非常耗时,我可以收到
OutofMemory
异常。有什么想法吗?

在一个线程上读取文件,将其行添加到一个线程中。启动从该队列读取的
N
任务。设置队列以防止内存不足错误。

您可以使用逐行读取文件,而无需立即将整个文件加载到内存中,也可以使用并行处理多个线程中的行:

Parallel.ForEach(File.ReadLines("file.txt"), (line, _, lineNumber) =>
{
    // your code here
});
比如:

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
,最简单的方法是使用
aspallel()
with degreeofparallelism(n)
来限制线程计数:

string filename = "C:\\TEST\\TEST.DATA";
int n = 5;

foreach (var line in File.ReadLines(filename).AsParallel().WithDegreeOfParallelism(n))
{
    // Process line.
}

正如上面提到的@dtb,读取文件然后处理文件中的各行的最快方法是: 1) 将文件.ReadAllLines()放入数组中 2) 使用Parallel.For循环在数组上迭代

您必须编写的代码的基本要点是:

string[] AllLines = File.ReadAllLines(fileName);
Parallel.For(0, AllLines.Length, x =>
{
    DoStuff(AllLines[x]);
    //whatever you need to do
});

在.Net4中引入更大的数组大小后,只要您有足够的内存,这就不应该成为问题。

在执行我自己的基准测试后,将61277203行加载到内存中,并将值推入字典/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);
  • File.ReadAllLines()和File.ReadAllLines().aspallel()在这种大小的文件上的运行速度几乎完全相同。看看我的CPU活动,他们似乎都使用了我8个内核中的两个
  • 首先使用File.ReadAllLines()读取所有数据似乎比在并行的.ForEach()循环中使用File.ReadLines()慢得多
  • 我还尝试了生产者/消费者或MapReduce样式的模式,其中一个线程用于读取数据,另一个线程用于处理数据。这似乎也没有超越上述简单模式
  • 我已经包含了此模式的一个示例以供参考,因为它不包含在本页中:

    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);
    
    var inputLines=new BlockingCollection();
    ConcurrentDictionary目录=新建ConcurrentDictionary();
    var readLines=Task.Factory.StartNew(()=>
    {
    foreach(File.ReadLines(catalogPath)中的var行)
    输入行。添加(行);
    inputLines.CompleteAdding();
    });
    var processLines=Task.Factory.StartNew(()=>
    {
    Parallel.ForEach(inputLines.GetConsumingEnumerable(),line=>
    {
    string[]lineFields=line.Split('\t');
    int genomoid=int.Parse(lineFields[3]);
    int-taxId=int.Parse(lineFields[0]);
    目录.TryAdd(基因组ID,taxId);
    });
    });
    Task.WaitAll(读取行、处理行);
    
    以下是我的基准:

    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())模式。但是,在这种情况下,它并没有出现。

    向我们展示您尝试过的方法创建唯一的n个随机数,按升序排序,使用
    文件。读取行
    ,在正确的位置获取行并将其传递给线程。您不使用以下方法吗:?使用thr=new Thread[j]重新编写它怎么样;对于(;iFile.ReadLines()的话,它基本上是一种类似python的生成器,在内部使用Yield?@daantimer我对python一无所知,但是File.ReadLines()只需返回一个IEnumerable,它通过
    yield
    实现。在这种情况下,您的答案可以合并为:是:-)我同意。我只想补充一点,ReadLines enumerable应该被分区。因为每一次并行执行都应该是为了一些重要的事情。可能对SteffenWinkler感兴趣。请注意,第三项在第1项结束后开始,而不是在第2项结束后开始。我不相信你的聚束担忧是正确的。@mjwills-Huh,在进一步的玩弄/测试之后,我不得不同意你的看法。我最初的观察肯定是巧合,否则我没有对发生的事情给予足够的关注。然而,我要注意的一点是Parallel.Foreach似乎将条目列表划分为可用线程的数量,每个线程执行一个子列表。所以线程1得到条目1-20,线程2得到条目21-40,而不是只得到下一个可用条目。如果你不想要这种行为,那就值得一读。也考虑删除你之前的(错误的)评论。嗨,卫国明,谢谢你分享这个基准。虽然我同意必须使用
    File.ReadLines()
    来避免大量内存消耗,但是
    Parallel.ForEach(File.ReadLines())
    真的比单线程处理好吗?流是按顺序设计的,而且硬件一次只支持读取一件东西,因此使用多个线程处理结果可能会增加阻塞和上下文切换的开销;查看简单处理
    File.Re的结果的性能指标会很有趣