在没有异步API的情况下如何并行化I/O操作

本文关键字:并行化 操作 情况下 异步 API | 更新日期: 2023-09-27 18:28:50

我正在开发一个远程扫描服务器并收集有关服务器元数据的应用程序。

我正在努力编写能够在我们的服务器上很好地扩展的代码。我正在使用TPL同时处理多个作业。我遇到的问题是,每个"作业"都要花费一半的时间等待I/O操作完成。

如果这些操作提供Async或Begin/End接口,但它们没有,那么这将非常容易修复。配对样品:

  • System.IO.Directory.GetAccessControl

  • Win32API调用,如FindFirstFilehttp://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx和FindNextFilehttp://msdn.microsoft.com/en-us/library/windows/desktop/aa364428(v=vs.85).aspx

在这种情况下,我如何确保我的应用程序做得更多?我是否应该为这些创建包装器,以便支持Async,并通过这种方式将它们发送到线程中进行处理。我是否应该尝试TPL实现生产者/消费者,以便同时执行所有这些I/O调用?TPL是否足够聪明,可以创建更多的线程,因为大多数线程都不会做任何事情?或者,在每个作业中,我应该将作业添加到ThreadPool中进行处理?

在没有异步API的情况下如何并行化I/O操作

如果您将大部分时间花在没有异步等价物的IO绑定操作上,那么加快它们速度的唯一方法就是使用大部分时间被阻塞的多个线程。

但根据IO的性质,您可能根本无法获得任何加速。例如,如果IO正在访问本地磁盘,那么使用单个线程很可能是最有效的选择。另一方面,如果你正在访问远程计算机,并且不受网络带宽的限制,那么使用多个线程可能是最好的选择。

TPL听起来是正确的解决方案,但TPL的哪一部分取决于您的代码。也许使用Parallel.ForEach()同时处理多个作业将是正确的解决方案。或者,您可能希望使用Tasks并行运行单个作业的某些部分。如果不了解更多细节,很难说。

我是否应该为这些创建包装器,以便支持Async,并通过这种方式将它们发送到线程中进行处理。

不,不要那样做。如果您在另一个线程上启动一个阻塞Task,然后使用await释放当前线程,那么您就没有获得任何东西(假设这是一个服务器应用程序)。有关更多信息,请参阅是否应该为同步方法公开异步包装器

TPL是否足够聪明,可以创建更多的线程,因为大多数线程都不会做任何事情?

是的,如果当前线程被阻塞,TPL倾向于使用更多的线程。但同时,您很可能希望限制线程数量(通常通过设置MaxDegreeOfParallelism之类的内容),这取决于您正在执行的IO类型。