我有非常大的文件需要阅读和处理。这可以使用线程并行完成吗?
这是我完成的一些代码。但是一个接一个地读取和处理文件似乎并没有缩短执行时间。
String[] files = openFileDialog1.FileNames;
Parallel.ForEach(files, f =>
{
readTraceFile(f);
});
private void readTraceFile(String file)
{
StreamReader reader = new StreamReader(file);
String line;
while ((line = reader.ReadLine()) != null)
{
String pattern = "\\s{4,}";
foreach (String trace in Regex.Split(line, pattern))
{
if (trace != String.Empty)
{
String[] details = Regex.Split(trace, "\\s+");
Instruction instruction = new Instruction(details[0],
int.Parse(details[1]),
int.Parse(details[2]));
Console.WriteLine("computing...");
instructions.Add(instruction);
}
}
}
}
最佳答案
看起来您的应用程序的性能主要受 IO 限制。但是,您的代码中仍有一些 CPU 密集型工作。这两部分工作是相互依赖的:在 IO 完成其工作之前,您的 CPU 密集型工作无法开始,并且在您的 CPU 完成前一个工作之前,IO 不会移动到下一个工作项目。他们都在互相扶持。因此,可能(在最底部解释)如果您并行执行 IO 和 CPU 绑定(bind)工作,您将看到吞吐量的提高,如下所示:
void ReadAndProcessFiles(string[] filePaths)
{
// Our thread-safe collection used for the handover.
var lines = new BlockingCollection<string>();
// Build the pipeline.
var stage1 = Task.Run(() =>
{
try
{
foreach (var filePath in filePaths)
{
using (var reader = new StreamReader(filePath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// Hand over to stage 2 and continue reading.
lines.Add(line);
}
}
}
}
finally
{
lines.CompleteAdding();
}
});
var stage2 = Task.Run(() =>
{
// Process lines on a ThreadPool thread
// as soon as they become available.
foreach (var line in lines.GetConsumingEnumerable())
{
String pattern = "\\s{4,}";
foreach (String trace in Regex.Split(line, pattern))
{
if (trace != String.Empty)
{
String[] details = Regex.Split(trace, "\\s+");
Instruction instruction = new Instruction(details[0],
int.Parse(details[1]),
int.Parse(details[2]));
Console.WriteLine("computing...");
instructions.Add(instruction);
}
}
}
});
// Block until both tasks have completed.
// This makes this method prone to deadlocking.
// Consider using 'await Task.WhenAll' instead.
Task.WaitAll(stage1, stage2);
}
我非常怀疑是你的 CPU 工作阻碍了一切,但如果是这种情况,你也可以像这样并行化第 2 阶段:
var stage2 = Task.Run(() =>
{
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
Parallel.ForEach(lines.GetConsumingEnumerable(), parallelOptions, line =>
{
String pattern = "\\s{4,}";
foreach (String trace in Regex.Split(line, pattern))
{
if (trace != String.Empty)
{
String[] details = Regex.Split(trace, "\\s+");
Instruction instruction = new Instruction(details[0],
int.Parse(details[1]),
int.Parse(details[2]));
Console.WriteLine("computing...");
instructions.Add(instruction);
}
}
});
});
请注意,如果您的 CPU 工作组件与 IO 组件相比可以忽略不计,您将看不到太多加速。与顺序处理相比,工作负载越均匀,流水线的性能就越好。
由于我们讨论的是性能,请注意,我对上述代码中的阻塞调用数量并不感到特别兴奋。如果我在自己的项目中这样做,我会选择异步/等待路线。在这种情况下,我选择不这样做,因为我想让事情易于理解和集成。
关于c# - 并行读取和处理文件 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20928705/