问题描述
比如说,我编写了一个程序,它应该读取给定中的所有文本文件并从中生成一个对象列表。
步骤是
我在质疑 .NET 中的 Parallel.ForEach(或任何其他并行构造)是否会提高步骤 1 的性能以及如何提高性能。磁盘的 IO 本质上不是同步的,即磁盘的磁头不能同时位于 5 个位置。事实上,它可能会使事情变慢?
您对此有何看法?
解决方法
让我们区分两个不同的概念:
- 并发:一次做不止一件事。
- 并行:通过在多个并发运行的线程之间划分来完成大量工作。
(这些定义来自Stephen Cleary's Concurrency in C# Cookbook。)
并发不需要多个执行器。它可以使用单个任务,并且可以使用上下文切换来在每项任务上取得进展。 (在给定的时间点,它会暂停给定任务的执行并切换到另一个作业。)
另一方面,当我们谈论并行处理时,我们可以假设有多个可用的执行器,这就是为什么多个作业可以同时取得进展的原因。
在 .NET 的情况下,当我们谈论并行编程时,我们大部分时间都指的是 CPU bound operations。这就是 Parallel.Foreach
、Parallel.For
和 Parallel.Invoke
专为多线程设计的原因。
如果您访问 related MSDN article,那么第一眼就会产生误导。它使用一个从给定文件夹读取文件的示例。不过请注意这条评论:
Parallel.ForEach(files,(currentFile) =>
{
// The more computational work you do here,the greater the speedup compared to a sequential foreach loop.
因此,根据您想做的工作,Parallel.XYZ
或 PLinq 可能不是最佳选择。如果您想同时执行多个异步 I/O 操作,那么 Task.WhenAll
是您最好的朋友。
如果您想更好地理解并行编程,那么我建议您阅读 Stephen Toub 的优秀白皮书:Patterns of Parallel Programming C#
我也鼓励您观看 Jeffry Richter 关于 async I/O 和 scalable applications 的演示。
,首先,SSD 现在无处不在,并且不会像旧 HDD 那样受到随机读取的影响。 RAID 设置(或 SAN)也可以执行大型并行操作。
但是如果您基本上是 IO 绑定,即您正在等待磁盘并且没有进行大量处理,那么不,并行运行没有意义.唯一会发生的就是你会有更多的等待线程,正如你所说,也会有更多的随机读取和更少的顺序。
让一个线程只做 I/O 而另一对做处理可能是有意义的,这样 I/O 队列深度保持很深,因为新的请求不断地通过。
如果您的代码在 CPU 上占用大量资源并且没有受到 I/O 的限制,那就是当您使用完全并行性时。例如解压、加密和解密。