.NET Parallel.Foreach 如何构造 IO 密集型操作

Ift*_*Ali 5 .net multithreading task-parallel-library parallel.foreach

比方说,我编写了一个程序,该程序应该读取给定的所有文本文件并从中生成对象列表。

所以步骤是

  1. 从磁盘读取给定文件夹中所有文件的文件内容。
  2. 每个文件内容创建唯一的对象。

我想知道 .NET 中的 Parallel.ForEach (或任何其他并行结构)是否会提高步骤 1 的性能以及如何提高。磁盘的IO本质上不是同步的吗即磁盘的磁头不能同时在5个地方。事实上,这可能会让事情变得更慢?

您对此有何看法?

Pet*_*ala 3

让我们区分两个不同的概念:

  • 并发:一次做多件事。
  • 并行性:通过将大量工作分配给并发运行的多个线程来完成。

(这些定义来自Stephen Cleary 的 Concurrency in C# Cookbook。)

并发不需要多个执行器。它可以与单个任务一起工作,并且可以使用上下文切换来在每项任务上取得进展。(在某个给定时间点,它会暂停给定任务的执行并切换到另一个作业。)

另一方面,当我们谈论并行处理时,我们可以假设有多个可用的执行器,这就是多个作业可以同时取得进展的原因。

并发与并行
来源


在 .NET 中,当我们谈论并行编程时,大多数时候我们指的是CPU 密集型操作。这就是为什么Parallel.Foreach,Parallel.ForParallel.Invoke是为多线程而设计的。

如果您访问相关的 MSDN 文章,那么乍一看它会产生误导。它使用一个从给定文件夹读取文件的示例。但请注意这条评论:

Parallel.ForEach(files, (currentFile) =>
{
    // The more computational work you do here, the greater the speedup compared to a sequential foreach loop.
Run Code Online (Sandbox Code Playgroud)

因此,根据您想要做什么的工作,Parallel.XYZPLinq 可能不是最佳选择。如果您想同时执行多个异步 I/O 操作,那么这Task.WhenAll是您最好的朋友。


如果您想更好地理解并行编程,那么我建议您阅读 Stephen Toub 的优秀白皮书:Patterns of Parallel Programming C#

我还鼓励您观看 Jeffry Richter 关于异步 I/O可扩展应用程序的演示。