【发布时间】:2018-08-27 02:50:13
【问题描述】:
我使用取消令牌,我想了解它是如何工作的。我有两个异步方法(在我的例子中是两个,但理论上我可以有 100 个)。 如果其中一个引发异常,我想取消所有异步方法中的工作。
我的想法是在调用所有方法的异常中取消令牌。当一个令牌被取消时,我希望其他方法停止工作,但这并没有发生。
using System;
using System.Threading;
using System.Threading.Tasks;
namespace CancelationTest
{
class Program
{
static void Main(string[] args)
{
new Test();
Console.ReadKey();
}
}
public class Test
{
public Test()
{
Task.Run(() => MainAsync());
}
public static async Task MainAsync()
{
var cancellationTokenSource = new CancellationTokenSource();
try
{
var firstTask = FirstAsync(cancellationTokenSource.Token);
var secondTask = SecondAsync(cancellationTokenSource.Token);
Thread.Sleep(50);
Console.WriteLine("Begin");
await secondTask;
Console.WriteLine("hello");
await firstTask;
Console.WriteLine("world");
Console.ReadKey();
}
catch (OperationCanceledException e)
{
Console.WriteLine("Main OperationCanceledException cancel");
}
catch (Exception e)
{
Console.WriteLine("Main Exception + Cancel");
cancellationTokenSource.Cancel();
}
}
public static async Task FirstAsync(CancellationToken c)
{
c.ThrowIfCancellationRequested();
await Task.Delay(1000, c);
Console.WriteLine("Exception in first call");
throw new NotImplementedException("Exception in first call");
}
public static async Task SecondAsync(CancellationToken c)
{
c.ThrowIfCancellationRequested();
await Task.Delay(15000, c);
Console.WriteLine("SecondAsync is finished");
}
}
}
即使第一种方法抛出异常,第二种方法也会完成工作并将任务延迟 15 秒。
结果是什么:
开始
第一次调用异常
SecondAsync 完成
你好
主要异常 + 取消
我希望 secondAsync 停止延迟并抛出 OperationCancelException。 我希望得到这样的结果:
开始
第一次调用异常
主要异常 + 取消
主要操作CanceledException 取消
我在哪里犯错了? 为什么方法 SecondAsync 完全执行并且不抛出异常?如果我更改 SecondAsync 和 FirstAsync 的顺序,而不是 SecondAsync 方法在令牌被取消时停止延迟并引发异常。
【问题讨论】:
-
合作取消:您的任务必须定期检查令牌,这需要循环。
-
@HenkHolterman OP 将
CancellationToken传递给Task.Delay。令牌发出信号时是否应该取消延迟? -
@PetSerAl - 是的,我忽略了这一点。虽然文档对延迟取消的时间有点模糊,但我认为这里可能仍需要 15 秒。
-
@Raskolnikov Cancellation 无法按照您的预期“订阅令牌取消事件”。
ThrowIfCancellationRequested只需检查令牌取消 是否 请求,如果是 - 抛出异常,但如果不是 - 它什么也不做。后期取消也不会抛出。 -
您也可以register a Delegate在请求取消时运行。
标签: c# async-await task