【问题标题】:How can I parallel split text file into multiple files in using c#如何在使用 c# 时将文本文件并行拆分为多个文件
【发布时间】:2014-12-04 03:47:14
【问题描述】:

我一直在研究,发现了 Parallel.For 的东西,但我不知道如何在没有某种错误的情况下对其进行编码。

我不断遇到的一个错误是,有多个处理器试图访问同一个文件。

我目前的代码是顺序的,但需要很长时间。我的文本文件是 10GB。

这是我的顺序部分,我所有的并行尝试都失败了

for (int i = 0; i <= 10; i++)
            {
               Console.WriteLine("Parsing List: " + i);
               min_chunk += chunk;
                max_chunk += chunk;
                if (max_chunk >= lines)
                {
                    max_chunk = lines - 1;
                }
                if (i == 0)
                {
                    min_chunk = 0;
                    max_chunk = chunk;
                }
                int diff = (int)(max_chunk - min_chunk);
                splitFile("sort.txt", min_chunk, max_chunk, i);
            }
public static void splitFile(string path, int min, int max, int threadnum)
        {

            string outFileName = String.Concat("list", threadnum, ".txt");
            System.IO.StreamWriter outfile = new System.IO.StreamWriter(outFileName);


            for (int currline = min; currline < max; currline++)
            {
                string line = File.ReadLines("sort.txt").Skip(currline).Take(1).First();
                outfile.WriteLine(line);
            }

            outfile.Close();
        }
    }

【问题讨论】:

  • 我建议您发布现有代码,我们可以帮助您解决问题所在。
  • 我想你会发现this answer 很有趣。尤其是关于没有得到任何速度提升的部分,因为您受 IO 限制。
  • 你应该对代码做一些度量。您很可能会发现您正在以磁盘驱动器的 ~max 传输速率读取文件。

标签: c# multithreading parallel-processing parallel.foreach


【解决方案1】:

这里有几个已经回答的与您的问题相关的链接

【讨论】:

    【解决方案2】:

    您不需要多个线程来加快速度。

    您真正想要的是读取文件一次,然后将其拆分。我不太明白你在用min_chunkmax_chunk 做什么,但我建议你定义一个块大小,比如10,000 行。然后你可以这样做:

    int maxLines = 10,000;
    int numLines = 0;
    int fileNumber = 0;
    var writer = File.CreateText("list" + fileNumber + ".txt");
    foreach (var line in File.ReadLines("sort.txt"))
    {
        writer.WriteLine(line);
        ++numLines;
        if (numLines == maxLines)
        {
            writer.Close();
            numLines = 0;
            ++fileNumber;
            writer = File.Create("list" + fileNumber + ".txt");
        }
    }
    writer.Close();
    

    使用多个线程来拆分单个文本文件通常不会加快速度。有两个原因。

    首先,如果你有 10 个线程,第一个线程读取前 N 行并输出它们。同时,第二个线程正在读取同一个文件,跳过前 N 行并写入接下来的 N 行。使用 10 个线程,您可以打开文件 10 次,除了一个线程之外的所有线程都花费大部分时间阅读和跳过它不关心的内容。

    另外,磁盘一次只能做一件事。当多个线程尝试写入单个磁盘时,它 比单个线程执行此操作。当单个线程正在写入磁盘时,它可以只写......然后写......然后写。当多个线程尝试写入时,一个写入,然后磁盘必须重新定位读/写头,然后才能为下一个线程写入,等等。这些重新定位(称为磁头寻道)需要很多时间——按顺序5 到 10 毫秒,这是 CPU 时间的永恒。发生的情况是您的线程大部分时间都在等待其他线程写入。

    更新

    如果由于某种原因您对使用多个线程执行此操作一无所知,则需要在您的 splitFile 方法中修复此循环:

            for (int currline = min; currline < max; currline++)
            {
                string line = File.ReadLines("sort.txt").Skip(currline).Take(1).First();
                outfile.WriteLine(line);
            }
    

    鉴于该循环和min = 100max = 200,那么它将读取文件100 次。第一次它会跳过 100 行并输出 1。然后它会关闭文件,下一次循环它会跳过 101 行并输出 1。这将需要相当长的时间。

    您可以将其更改为:

    foreach (var line in File.ReadLines("sort.txt").Skip(min).Take(max-min))
    {
        outfile.WriteLine(line);
    }
    

    事实上,如果你真的想变得花哨,你可以这样写:

    File.WriteAllLines(outFileName, File.ReadLines("sort.txt").Skip(min).Take(max-min));
    

    但是你仍然有多个线程试图访问同一个输入文件的问题。如果File.ReadLines 以独占模式打开文件,那么您有两种选择:

    1. 使用锁防止多个文件同时尝试访问该文件
    2. 使用许可共享打开文件

    选项 2 的示例:

    using (var fs = new FileStream("sort.txt", FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        using (var reader = new StreamReader(fs))
        {
            int i = 0;
            while (!reader.EndOfStream && i < max)
            {
                string line = reader.ReadLine();
                if (i > min)
                    outfile.WriteLine(line);
                ++i;
            }
        }
    }
    

    这将满足您的要求。不过,这并不是一种非常聪明的处理方式,因为您有 10 个线程同时读取同一个文件,而且它们中的大多数都花时间跳过行。你正在做很多不必要的工作。我首先介绍的简单单线程版本将胜过此版本,尤其是当输出文件都在同一个驱动器上时。

    【讨论】:

    • 感谢吉姆的回复,我不想写入同一个文件。我正在尝试读取一个通用文件(sort.txt)并将其分解为 n 个不同的文件。我在 c++ 上使用 openmp 进行了尝试,效果很好,但使用 c# 是一次艰难的经历,直到我做对了,我才能停下来。
    • @BisoyeOlaleye:我提供的代码确实将单个文件分解为 n 个不同的文件。我关于磁盘的观点与多个线程写入同一个文件没有任何关系,而是多个线程写入同一个磁盘驱动器上的不同文件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 2013-04-22
    • 1970-01-01
    相关资源
    最近更新 更多