使用任务并行库执行异步I / O的建议

时间:2010-05-13 03:19:01

标签: asynchronous .net-4.0 task-parallel-library

我有一些高性能的文件传输代码,我在C#中使用异步编程模型(APM)习语(例如BeginRead / EndRead)编写。此代码从本地磁盘读取文件并将其写入套接字。

为了在现代硬件上获得最佳性能,尽可能在飞行中保留多个出色的I / O操作非常重要。因此,我在文件上发布了几个BeginRead操作,然后当一个完成时,我在套接字上调用BeginSend,当完成时,我在文件上再做一个BeginRead。细节有点复杂,但在高层次上就是这个想法。

我已经使用基于APM的代码,但是很难遵循并且可能存在细微的并发错误。我很乐意为此使用TPL。我认为Task.Factory.FromAsync就是这么做的,但是有一个问题。

我见过的所有I / O示例(最特别是Parallel Extensions Extras中的StreamExtensions类)假定一次读取后跟一次写入。这不会按我需要的方式执行。

我不能使用简单的Parallel.ForEach或Extras扩展Task.Factory.Iterate这样的东西,因为异步I / O任务不会花太多时间在工作线程上,所以Parallel只启动另一个任务,可能导致数十或数百个待处理的I / O操作;方式太多了!您可以通过Wait执行任务来解决这个问题,但这会导致创建事件句柄(内核对象),以及对任务等待句柄进行阻塞等待,从而占用工作线程。我的基于APM的实现避免了这两件事。

我一直在玩不同的方法来保持飞行中的多个读/写操作,我已经设法使用延续调用创建另一个任务的方法,但它感觉很尴尬,并且肯定没有感觉像惯用的TPL。

还有其他人在使用TPL时遇到过这样的问题吗?有什么建议吗?

1 个答案:

答案 0 :(得分:2)

如果您担心线索太多,可以在ParallelOptions.MaxDegreeOfParallelism的通话中将Parallel.ForEach设置为可接受的号码。