我一直在研究,我发现了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();
}
}
这里有一些已经回答的与您的问题相关的链接
- 拆分大文件
- 并行 C#
- 将文本文件拆分为多个
您不需要多个线程来加快速度。
您真正想要的是读取文件一次,然后随时拆分。我真的不明白你在用min_chunk
和max_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 = 100
和max = 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
以独占模式打开文件,则有两种选择:
- 使用锁可防止多个文件尝试同时访问文件
- 使用宽松共享打开文件
选项 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 个线程同时读取同一个文件,并且其中大多数线程都花时间跳过行。你正在做很多不必要的工作。我首先介绍的简单单线程版本将优于此版本,特别是如果输出文件都在同一驱动器上。