如果抛出异常,则取消所有异步方法 [英] Cancel all async methods if one throws an exception

查看:32
本文介绍了如果抛出异常,则取消所有异步方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用取消令牌,我想了解它是如何工作的.我有两个异步方法(在我的例子中是两个,但理论上我可以有 100 个).如果其中一个引发异常,我想取消所有异步方法中的工作.

I play with cancelation token, and I would like to understand how this works. I have two async methods(in my example two but in theory I can have 100). I want to cancel work in all async methods if one of them throws an exception.

我的想法是在调用所有方法的异常中取消令牌.当令牌被取消时,我希望其他方法停止工作,但这并没有发生.

My idea is to cancel token in exception where all methods are called. When a token is canceled I would expect that other method stop working, but this is not happening.

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 秒.

The second method finish work and delay task for 15 seconds even when the first method throws an exception.

什么是结果:

开始

第一次调用异常

SecondAsync 完成

SecondAsync is finished

你好

主要异常 + 取消

我希望 secondAsync 停止延迟并抛出 OperationCancelException.我希望这个结果:

I would expect that secondAsync stop delay and throw OperationCancelException. I would expect this result:

开始

第一次调用异常

主要异常 + 取消

主操作CanceledException取消

Main OperationCanceledException cancel

我哪里出错了?为什么方法 SecondAsync 被完全执行并且不抛出异常?如果我更改 SecondAsync 和 FirstAsync 的顺序,那么当取消令牌并抛出异常时,Second 方法会停止延迟.

Where am I making mistake? Why method SecondAsync is fully executed and doesn't throw an exception? And if I change the order of SecondAsync and FirstAsync than Second method stop to delay when the token is canceled and throw an exception.

推荐答案

因为你的代码的相关部分是:

Because the relevant part of your code is:

try
{
   ...
   await secondTask;
   await firstTask;
}
catch(...)
{
    source.Cancel();
}

现在,当 firstTask 启动并抛出时,它会在 secondTask 之后等待.在等待任务之前,异常不会在调用者中出现.因此 catch 子句只会在 secondTask 已经完成后执行.Cancel() 发生得太晚了.

Now while the firstTask is started and has thrown, it is awaited after the secondTask. The exception won't surface in the caller until the task is awaited. And so the catch clause will only execute after secondTask has already completed. The Cancel() is just happening too late.

如果你想让你的 firstTask 打断第二个,你必须

If you want your firstTask to interrupt the second one you will have to

  1. 将源传递到 FirstAsync 并在那里调用 Cancel().有点丑.
  2. 改变等待结构.我认为你的样本有点人为.使用 Parallel.Invoke() 或类似的东西,它会很自然地发生.

这篇关于如果抛出异常,则取消所有异步方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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