目錄
- 前言
- async-void-方法的例外無法被捕獲
- 注意
- 測驗
- 崩潰
- 注意
- 不崩潰
- 崩潰
來源:https://note.guoqianfan.com/2022/04/23/dont-use-async-void/
前言
之前都是在檔案里看到:除了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!");
});
}
學無止境
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/462829.html
標籤:.NET技术
