繁体   English   中英

是否可以在ExecuteReader中使用CancellationToken?

[英]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

我无法对您的编辑做出权威性的答复,但是关于初始问题,您应该了解以下几点:

  1. Task.Run( ... ).Result阻塞; 该语法有点误导。
  2. await Task.Run( () => command.ExecuteReaderAsync(token)); 将仅阻塞执行方法的其余部分; 允许将其余部分视为回调。
  3. await Task.Run( () => command.ExecuteReaderAsync(token), token); 如上工作,但允许任务并行库也遵循您的取消令牌。

对于主要问题, 这篇msdn文章建议ExecuteReaderAsync()真正兑现了cancelToken。 请记住,框架中有两种方法实际上不会这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM