关于c#:async-void-导致程序崩溃

起源:https://note.guoqianfan.com/2…

前言

之前都是在文档里看到:除了winform的事件能够应用async void,其余状况下相对不能应用async void,而是要用async Task

对于这个标准,尽管不是很明确内里起因,然而始终恪守着。

直到这天看到了这篇博客:在 ASP.NET Core 中誤用 async void 竟引發了 502(Bad Gateway),说async void里出现异常时会导致程序解体。钻研测试了一番,终于明确起因。

摘录重点如下:

根據使用者提供的另一個線索「網站的某個性能壞了」,我們繼續往下追究,從程式碼當中我看到了一個近期新加的办法,它应用了 async void,沒錯,它应用了 async void,而且很可怜地它會發生 Exception,更慘的是這個 Exception 沒有被處理。

對 C# 非同步程式設計有理解的敌人,看到這邊應該大抵上能够晓得是發什麼問題了,async void 是建議應該防止应用的宣告形式,其中一個起因就是當 async void 办法發生 Exception 時無法從呼叫端捕獲,即便加了 try…catch… 也沒用,async void 办法就有點像是我們本人起了另一個 Thread 去執行程式一樣,執行的過程中如果發生 Exception 沒有去處理,Exception 就會一路被往上拋,最終在 AppDomain 層級被捕獲,然後我們的應用程式就掛了。

async-void-办法的异样无奈被捕捉

async void办法抛出的异样无奈被捕捉,异样会被始终往上面抛,最终在AppDomain层级被捕捉,而后程序就挂了。

示例代码如下:

[HttpGet]
public async void Get()
{
    try
    {
        ThrowExceptionAsync();
    }
    catch (Exception ex)
    {
        //这里不能捕捉到异样,程序解体!
        _logger.LogInformation(ex, "ex...");
    }
}

async void ThrowExceptionAsync()
{
    throw new Exception("async void ex!");
}

留神

后面所说的是 async void办法抛出的无奈预知到的异样。在async void办法外部,咱们依然可能应用try catch,逻辑是失常逻辑。具体见上面的示例:

[HttpGet]
public async void Get()
{
    //在async void办法外部,咱们依然可能应用try catch,逻辑是失常逻辑。
    //此处try catch是无效的。异样被捕捉解决了,async void办法执行无异样,不会导致程序解体。
    try
    {
        await Task.Run(() =>
        {
            throw new Exception("ex!");
        });
    }
    catch (Exception ex)
    {
        _logger.LogInformation(ex,"ex...");
    }
}

测试

解体

出现异常时能导致解体的代码有2种,如下:

[HttpGet]
public async void Get()
{
    //异样会导致程序解体
    throw new Exception("ex!");
}

[HttpGet]
public async void Get()
{
    //异样会导致程序解体
    await Task.Run(() =>
    {
        throw new Exception("ex!");
    });
}

留神

上面的async void代码不会抛异样。

[HttpGet]
public async void Get()
{
    Task.Run(() =>
    {
        throw new Exception("ex!");
    });
}

代码里的async void没问题(不抛异样),其实也合乎逻辑。因为async void外面没有异样,天然就不会导致程序解体。

异样在Task.Run外面,因为没有应用await进行期待,那么异样就是被线程池线程捕捉的,它们捕捉到后,不会再往上面抛了,间接本人外部消化掉了。

因为async void在执行时没有异样,天然就不会导致程序解体。

然而因为咱们不能保障所有代码都没有异样,所以不要应用async void

不解体

只有不是async void,就算申请处理程序抛出了异样,也不会影响到主线程的。最多就是这次申请出错,返回500 Internal Server Error而已。

测试的几种代码如下:

[HttpGet]
public async Task Get()
{
    //500错误码
    throw new Exception("ex!");
}

[HttpGet]
public async Task Get()
{
    //500错误码
    await Task.Run(() =>
    {
        throw new Exception("ex!");
    });
}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理