这个问题可以通过MSDN中的以下引用来描述:
在异步方法期间将忽略CommandTimeout属性调用,如BeginExecuteReader。
在谷歌上搜索这个问题的解决方案时,我偶然发现了许多建议将Task.Factory.FromAsync
与ThreadPool.RegisterWaitForSingleObject
结合使用的帖子。
关于SO,人们可以在这里和这里查看,尽管这两个讨论的是异步web请求,而不是SQL命令。但问题是一样的——从异步SQL命令/Web请求中超时。
建议的方法是调用Task.Factory.FromAsync
,然后调用ThreadPool.RegisterWaitForSingleObject
以等待或超时对应于任务的句柄。
我不明白这里有什么。异步IO方法利用IO完成端口回调来返回结果。当这样的IO操作开始时,调用线程会返回到线程池中,供其他请求重用。
另一方面,根据MSDN:
RegisterWaitForSingleObject方法将指定的委托排队到线程池
和
等待线程使用Win32 WaitForMultipleObjects函数监视已注册的等待操作。
这意味着它会阻塞线程池线程,直到我们的异步IO返回或发生超时。如果我的理解是正确的,那么如果我们使用这种技术,那么正在进行的N个异步IO将阻塞并锁定N个线程池线程。
但是,在这种情况下使用异步IO有什么意义呢?CCD_ 5杀死了IOCP的所有优点。
另一方面,根据MSDN的博客,RegisterWaitForSingleObject
优化了等待,将同一线程的多个句柄批处理成一个对WaitForMultipleObjects
的调用,这反过来又受到它可以等待的句柄数量的限制,即64个。
那么,如果每个请求从同一线程发出65个异步IO请求并结合RegisterWaitForSingleObject
,那么有多少线程池线程(b)被锁定?
那么,如果每个请求都有65个异步IO请求与RegisterWaitForSingleObject一起从同一线程发出,那么有多少线程池线程被锁定?
两个(对于RegisterWaitForSingleObject
调用)-每个ThreadPool线程可以处理64个请求(从技术上讲,这是MAXIMUM_WAIT_OBJECTS
的值,实际上是64)。
后者不是扼杀了前者的效用吗?
没有。它确实降低了它的有效性,但由于RegisterWaitForSingleObject
中有线程池,所以它并没有破坏它的有用性。
请注意,在C#5中,我通常会使用带有超时的async
/await
支持来处理此问题。Task.Delay
可以简单地用于处理此问题,也可以使用Timer制作一个扩展方法来处理任何Task
上的超时。