简体   繁体   English

不可等待的方法异常导致不一致的行为

[英]Not awaitable method exception thowing inconsistent behaviour

So I read on async/await and somewhere, someplace I read that if you don't await an async method you basically lose it.所以我在 async/await 和某个地方读到过,如果你不等待异步方法,你基本上会丢失它。 It fires and forgets and goes into the AEeher and if it throws an exception - you will never know.它触发并忘记并进入AEeher,如果它抛出异常 - 你永远不会知道。
This was the example the author used:这是作者使用的示例:

    static async void OnButtonClick()
    {
        yolo();
        string imageUrl = null;
        try
        {
            DownloadAndBlur(imageUrl);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Exception: {ex}");
        }
        Console.WriteLine("Done!");
    }

    static async Task DownloadAndBlur(string url)
    {
        if (url == null)
        {
            throw new ArgumentNullException(nameof(url));
        }
    }

Indeed, if I call the OnButtonClick() method from my code no exception gets thrown, or rather, nothing about an exception is printed on the console.实际上,如果我从我的代码中调用OnButtonClick()方法,则不会引发异常,或者更确切地说,控制台上不会打印任何有关异常的信息。 While if I await the DownloadAndBlur method - an exception is written to the console.而如果我等待DownloadAndBlur方法 - 一个异常被写入控制台。

So I tried to replicate the behaviour and wrote this:所以我试图复制这种行为并写了这个:

    static async void Execute()
    {
        Console.WriteLine(1);
        yolo();
        Console.WriteLine(2);
    }

    static Task yolo()
    {
        throw new Exception();
    }

But an exception is thrown and my debugging session catches it.但是抛出了一个异常,我的调试 session 捕获了它。 So what is different, because I think they are the same.那么有什么不同,因为我认为它们是相同的。

The Execute method is not fire-and-forget. Execute方法不是一劳永逸的。 It is async void .它是async void

static async void Execute()
{
    YoloAsync();
}

Exceptions in async void methods are thrown in the current SynchronizationContext (or in the ThreadPool if the SynchronizationContext.Current is null), which normally results to the crashing of the process ( source code ). async void方法中的异常会在当前SynchronizationContext中抛出(如果SynchronizationContext.Current为 null,则在ThreadPool中),这通常会导致进程崩溃( 源代码)。

Next, the YoloAsync method is not marked with the async modifier.接下来, YoloAsync方法没有用async修饰符标记。

static Task YoloAsync()
{
    throw new Exception();
}

Semantically it is an asynchronous method since it returns a Task , but the task is not generated from an async-state-machine.语义上讲,它是一个异步方法,因为它返回一个Task ,但该任务不是从异步状态机生成的。 So the code inside the YoloAsync method is executed synchronously like any other method, and unlike the async-state-machine-generated methods that propagate their exceptions through the Task they return.因此, YoloAsync方法中的代码像任何其他方法一样同步执行,与通过返回的Task传播异常的异步状态机生成的方法不同。

Maxim 26. "Fire and Forget" is fine, provided you never actually forget.格言 26。“一劳永逸”很好,前提是你永远不会真正忘记。

Getting a Exception in Multitasking is always difficulty.在多任务处理中获得异常总是很困难的。

If you are doing Mutlthreading, it is actually trivially easy to loose all exceptions by default.如果你在做多线程,默认情况下很容易释放所有异常。 The thread itself swallows all Exceptions.线程本身会吞下所有异常。 This is the worst case that has to be handeled.这是必须处理的最坏情况。

As a result, Multitasking approaches always catch all exceptions, then expose them in the Result.因此,多任务方法总是捕获所有异常,然后将它们暴露在结果中。 Task has a property for that . Task 有一个属性 So Does RunWorkerCompletedEventArgs . RunWorkerCompletedEventArgs也是如此。

One job of the continuation code, is to check for and re-raise any Exceptions.延续代码的一项工作是检查并重新引发任何异常。 It is something Task has to do for Multithreading support, even if it does not nessearily make sense with mere Multitasking.这是 Task 必须为多线程支持做的事情,即使它对于单纯的多任务处理没有意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM