Task.WaitAll引发OperationCanceledException [英] Task.WaitAll throws OperationCanceledException

查看:58
本文介绍了Task.WaitAll引发OperationCanceledException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个正在运行的任务列表,它们具有相同的 CancellationTokenSource .

I have a list of running tasks with the same CancellationTokenSource.

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

I want the current thread to wait until all the tasks complete or until the tasks were cancelled.

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

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

The tasks might be cancelled by another task even when the current thread is in a waiting state. This is normal behavior.

但是,当当前线程处于等待状态并且另一个任务取消了任务时,WaitAll会抛出 CancellationTokenSource 并显示一条消息:操作已取消.".

However, while the current thread is in waiting state and another task cancel the tasks, the WaitAll throws CancellationTokenSource with a message: "The operation was canceled.".

我知道它已被取消,我是故意这样做的.我只希望它在取消或完成任务后继续下一个代码,而不会引发异常.

I know it was cancelled, I did it intentionally. I just want it to continue to the next code after the tasks were cancelled or completed, without throwing an exception.

我知道我可以使用try&包装此代码捕获但引发异常是繁重的操作,我不希望这种异常发生在这样的正常行为上.

I know I can wrap this code with try & catch but throwing an exception is heavy operation and I don't want it to happen on a normal behavior like this.

推荐答案

此阻止机制可以表述为:

This blocking mechanism can be rephrased as:

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

这给您带来了一项任务,我们可以等待,但也可以管理取消任务.因此,要忽略取消异常,您可以执行以下操作:

This gives you a task back which we can await but can also manage cancellation from. So, to ignore cancellation exception, you can do the following:

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

不会抛出 OperationCancelledException .

然后可以将其包装到扩展方法中,如下所示:

This could then be wrapped into an extension method as follows:

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

这将允许您再次编写以下内容,而不会遇到 OperationCancelledException :

Which would allow you to write the following, again without encountering an OperationCancelledException:

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

这是一个测试夹具,显示了该方法的工作原理:

Here's a test fixture showing the approach working:

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();
    }
}

希望有帮助.

这篇关于Task.WaitAll引发OperationCanceledException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆