是否可以在ExecuteReader中使用CancellationToken ?

本文关键字:CancellationToken ExecuteReader 是否 | 更新日期: 2023-09-27 18:03:30

新的异步ExecuteReaderAsync接受一个CancellationToken。有没有办法取消旧的同步ExecuteReader ?

在我们的例子中,所有的数据操作在一个后台线程上是同步的,所以await不是一个选项。我不想启动第二个线程- Task.Run(() => command.ExecuteReaderAsync(token)).Result似乎只是为了能够从UI线程取消浪费。

是否可以在ExecuteReader中使用CancellationToken ?

性能测试显示,与使用Begin或Async api及其线程池延续相比,使用专用同步数据读取线程的性能优势几乎是前者的两倍。(由于数以千万计的行将在几秒钟内加载,因此在这种情况下我们更喜欢性能。)

方便令牌传递的扩展方法:

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()确实尊重那个cancellationToken。请记住,框架中有几个方法实际上不会这样做。

相关文章:
  • 没有找到相关文章