[英]Is it possible to use a CancellationToken with ExecuteReader?
新的异步ExecuteReaderAsync
采用CancellationToken。 有什么办法可以取消旧的同步ExecuteReader
吗?
在我们的例子中,所有数据操作都是在后台线程上同步的,因此await
不是一个选择。 我不想启动第二个线程Task.Run(() => command.ExecuteReaderAsync(token)).Result
似乎是浪费,只是能够从UI线程中取消。
性能测试表明,与使用具有线程池连续性的Begin或Async API相比,使用专用的同步数据读取线程将使性能提高近2倍。 (由于将在几秒钟内加载数千万行,因此在这种情况下,我们更喜欢性能。)
用于方便令牌传递的扩展方法:
public static SqlDataReader ExecuteReader(this SqlCommand command, CommandBehavior commandBehavior, CancellationToken cancellationToken)
{
try
{
using (cancellationToken.Register(command.Cancel))
return command.ExecuteReader(commandBehavior);
}
catch (SqlException) when (cancellationToken.IsCancellationRequested)
{
throw new OperationCanceledException(cancellationToken);
}
}
我对Reflector反编译做了一些摸索。 Begin和Async版本都非常节省,但是它们都完全基于TPL异步。 因此,在这两个线程上都有用于连续的线程池调度。
此扩展方法没有线程开销。 在令牌源上调用Cancel
的线程还将调用command.Cancel
,这将立即在数据线程中导致SqlException
。
我无法对您的编辑做出权威性的答复,但是关于初始问题,您应该了解以下几点:
Task.Run( ... ).Result
阻塞; 该语法有点误导。 await Task.Run( () => command.ExecuteReaderAsync(token));
将仅阻塞执行方法的其余部分; 允许将其余部分视为回调。 await Task.Run( () => command.ExecuteReaderAsync(token), token);
如上工作,但允许任务并行库也遵循您的取消令牌。 对于主要问题, 这篇msdn文章建议ExecuteReaderAsync()真正兑现了cancelToken。 请记住,框架中有两种方法实际上不会这样做。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.