的任务.WaitAll抛出OperationCanceledException

本文关键字:OperationCanceledException 抛出 WaitAll 任务 | 更新日期: 2023-09-27 18:18:04

我有一个相同CancellationTokenSource的运行任务列表。

我希望当前线程等待直到所有任务完成直到任务被取消。

Task.WaitAll(tasks.ToArray(), searchCencellationTokenSource.Token);
System.Console.WriteLine("Done !");

即使当前线程处于等待状态,任务也可能被另一个任务取消。这是正常行为。

然而,当当前线程处于等待状态并且另一个任务取消任务时,WaitAll抛出CancellationTokenSource并传递消息:" the operation was cancelled ."

我知道它被取消了,我是故意的。我只是希望它在任务被取消或完成后继续执行下一个代码,而不抛出异常。

我知道我可以用try &catch但是抛出异常是一个繁重的操作,我不希望它发生在像这样的正常行为

的任务.WaitAll抛出OperationCanceledException

这个阻塞机制可以改写为:

Task.WhenAll(taskA, taskB, taskC).Wait()

这给你一个任务返回,我们可以等待,但也可以管理取消。因此,要忽略取消异常,您可以执行以下操作:

Task.WhenAll(taskA, taskB, taskC).ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled).Wait();

不会抛出OperationCancelledException

然后可以像这样包装成一个扩展方法:

public static class TaskExtensions
{
    public static Task IgnoreCancellation(this Task task)
    {
        return task.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled);
    }
}

这将允许您编写以下内容,同样不会遇到OperationCancelledException:

Task.WhenAll(taskA, taskB, taskC).IgnoreCancellation().Wait();

下面是一个测试夹具,显示了该方法的工作:

public class IgnoreTaskCancellation
{
    [Fact]
    public void ShouldThrowAnAggregateException()
    {
        CancellationTokenSource cts = new CancellationTokenSource(10);
        Task taskA = Task.Delay(20, cts.Token);
        Task taskB = Task.Delay(20, cts.Token);
        Task taskC = Task.Delay(20, cts.Token);
        Assert.Throws<AggregateException>(() => Task.WhenAll(taskA, taskB, taskC).Wait());
    }
    [Fact]
    public void ShouldNotThrowAnException()
    {
        CancellationTokenSource cts = new CancellationTokenSource(10);
        Task taskA = Task.Delay(20, cts.Token);
        Task taskB = Task.Delay(20, cts.Token);
        Task taskC = Task.Delay(20, cts.Token);
        Task.WhenAll(taskA, taskB, taskC).ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled).Wait();
    }
    [Fact]
    public void ShouldNotThrowAnExceptionUsingIgnore()
    {
        CancellationTokenSource cts = new CancellationTokenSource(10);
        Task taskA = Task.Delay(20, cts.Token);
        Task taskB = Task.Delay(20, cts.Token);
        Task taskC = Task.Delay(20, cts.Token);
        Task.WhenAll(taskA, taskB, taskC).IgnoreCancellation().Wait();
    }
}

希望能有所帮助。

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