为什么OperationCancelledException传递的是与CTSource不同的CancellationToken?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么OperationCancelledException传递的是与CTSource不同的CancellationToken?相关的知识,希望对你有一定的参考价值。

为什么在异常中存储的CancellationToken与CancellationTokenSource提供的令牌不同?

[Test]
public static async Task SqlCommand_should_recognise_which_CT_triggered_its_cancellation()
{

    var timeout = TimeSpan.FromSeconds(1);
    var cts = new CancellationTokenSource(timeout);

    try
    {
        var connection = new SqlConnection(_config.ConnectionString);
        await connection.OpenAsync(cts.Token);
        var sqlQuery = new SqlCommand("select 1", connection);

        await Task.Delay(timeout + TimeSpan.FromSeconds(1));
        await sqlQuery.ExecuteScalarAsync(cts.Token);
    }
    catch (OperationCanceledException cancelledEx)
    {
        //Shouldn't they be the same?
        Assert.AreEqual(cancelledEx.CancellationToken, cts.Token);
        // The below fails as well
        // Assert.IsTrue(cancelledEx.CancellationToken == cts.Token);


    }
}
答案

为什么在异常中存储的CancellationToken与CancellationTokenSource提供的令牌不同?

这是一个实现细节。我没有看过消息来源,但我怀疑正在发生的事情是提供给CancellationTokenExecuteScalarAsync正在与一些内部CancellationToken相结合,这意味着“我们失去了联系”或类似的东西。这些linked CancellationTokens不等同于他们的来源CancellationTokens。

这是CancellationTokens的一般使用问题。使用链接的令牌,并不总是可以确定哪个取消令牌导致取消。因此,我建议您通过catch (OperationCanceledException ex) when (cts.IsCancellationRequested)检查自己的取消令牌副本:

static async Task Main(string[] args)
{
  var timeout = TimeSpan.FromSeconds(1);
  var cts = new CancellationTokenSource(timeout);

  try
  {
    await IndirectDelay(10, cts.Token);

    await Task.Delay(timeout + TimeSpan.FromSeconds(1));
    await IndirectDelay(10, cts.Token);
  }
  catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
  {
    Console.WriteLine(ex.CancellationToken == cts.Token); // false
    Console.WriteLine("Our token is canceled.");
  }
  catch (OperationCanceledException)
  {
    Console.WriteLine("Canceled for some other reason.");
  }
  catch (Exception)
  {
    Console.WriteLine("General error.");
  }
}

private static async Task IndirectDelay(int timeout, CancellationToken token)
{
  using (var internalCts = new CancellationTokenSource())
  using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token, internalCts.Token))
    await Task.Delay(timeout, cts.Token);
}

存在竞争条件的可能性,您的代码会认为由于超时而发生取消,但实际上是因为连接丢失(或者内部逻辑正在发生),但在大多数情况下这并不重要。

以上是关于为什么OperationCancelledException传递的是与CTSource不同的CancellationToken?的主要内容,如果未能解决你的问题,请参考以下文章

Redis 为什么面试都问我却不懂?因为它快吗?它为什么快?

CodeBlocks中这是为啥啊

为什么选择容器技术,又为什么选择了kubernetes?

Full GC为什么那么慢?为什么老年代垃圾回收效率比新生代低很多?为什么Minor gc速度比Major GC慢?

转载 JavaWeb项目为什么我们要放弃jsp?为什么要前后端解耦?为什么要动静分离?

如何回答「为什么想做产品经理」面试核心问题3