C# 没有异步API时如何并行I/O操作

C# 没有异步API时如何并行I/O操作,c#,asynchronous,task-parallel-library,async-await,C#,Asynchronous,Task Parallel Library,Async Await,我正在开发一个远程扫描服务器并收集服务器元数据的应用程序 我正在努力编写能够在我们的服务器上很好地扩展的代码。我使用TPL同时处理多个作业。我遇到的问题是,这些“作业”中的每一项都要花费一半的时间等待I/O操作完成 如果这些操作提供异步或开始/结束接口,但它们没有,那么这将很容易修复。两个样本: System.IO.Directory.GetAccessControl Win32API调用,如FindFirstFile和FindNextFile 如何确保我的应用程序在这种情况下做得更多?我是

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

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

如果这些操作提供异步或开始/结束接口,但它们没有,那么这将很容易修复。两个样本:

  • System.IO.Directory.GetAccessControl

  • Win32API调用,如FindFirstFile和FindNextFile

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

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

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

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

我是否应该为它们创建包装器,以便支持异步,这样它们就可以在线程中进行处理

不,不要那样做。如果您在另一个线程上启动阻塞
任务
,然后使用
等待
释放当前线程,则您没有获得任何东西(假设这是一个服务器应用程序)。有关详细信息,请参阅

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


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

为什么不启动一个执行您想要的任务呢?顺便说一句,Win32 API调用通常足够快,不需要异步。那些有和没有.NET等价物的查询通常需要针对每种情况进行特殊处理,例如特殊回调、轮询。另外,使用.NET API的WMI查询可以使用TaskCompletionSource转换为任务。您能给出一些需要异步运行的Win32和WMI调用的示例吗?有些Win32 API调用提供异步接口,只是它们不遵循.Net约定。这正是异步
FileStream
操作的实现方式。@PanagiotisKanavos启动
任务
仍然意味着线程被阻塞,因此它不太可能有帮助。我说过它们需要特殊处理。至于异步执行阻塞操作是否有帮助?这取决于具体情况,这就是我要求提供细节的原因。并行运行10个操作比按顺序运行10个操作要好,但运行100个操作可能不可行。我认为在不了解具体情况的情况下,你不可能做出广泛的假设