.net core 拋異常對性能影響的求證之路
- 2022 年 6 月 11 日
- 筆記
- Asp.Net Core, 性能優化, 異常性能影響
一、前言
在.net 社區中曾經聽到過很多關於大量拋異常會影響性能這樣的結論,心中一直就存在各種疑問。項目中使用自定義異常來處理業務很爽,但是又擔心大量拋業務異常存在性能問題。
查閱了各種文檔,微軟官方對性能優化這一塊也不建議使用過多的異常,故我心中冒出疑問。
- 疑問一:項目中大量拋出業務異常對性能是否會受到影響?
二、求證
2.1 使用.net 6 建立了一個簡單的web api 項目 新增兩個壓測介面
- api介面程式碼如下
/// <summary>
/// 正常返回數據介面1
/// </summary>
/// <returns></returns
[HttpGet("Test1")]
public async Task<IActionResult> Test()
{
return Content("1");
}
/// <summary>
/// 拋異常返回介面2 ,同時存在全局過濾器
/// </summary>
/// <returns></returns
[HttpGet("Test2")]
public async Task<IActionResult> Test2(string open)
{
throw new BusinessException(Model.EnumApiCode.SignWrong);
}
- 全局過濾器程式碼如下
/// <summary>
/// 全局異常日誌
/// </summary>
public class ExceptionFilter : IExceptionFilter
{
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public void OnException(ExceptionContext context)
{
//不做任何處理,直接返回1
context.Result = new JsonResult("1");
}
}
這裡注入過濾器程式碼就不貼上來
-
現在對test1 介面並發200的情況下進行壓測,持續15分鐘的壓測結果如下:

-
對通過全局過濾器捕獲異常並大量拋出異常 在相同壓測條件情況下的壓測結果如下:

- 對test1 和test2 同等條件下壓測結果對比
| 介面 | tps | cpu | 壓測條件 |
|---|---|---|---|
| test1 | 10300左右 | cpu消耗90%左右 | 並發200,持續壓測 |
| test1 | 4300左右 | cpu消耗100%左右 | 並發200,持續壓測 |
目前得到的結論是拋異常確實影響性能,並且對性能下降了60% 左右,上面主要是異常流程走了全局過濾器方式,故參考意義不大,下面再進一步修改程式碼進行壓測
- 對test2 程式碼進行修改如下
/// <summary>
/// 拋異常返回介面2 ,直接try catch 不走全局過濾器
/// </summary>
/// <returns></returns
[HttpGet("Test2")]
public async Task<IActionResult> Test2()
{
try
{
throw new BusinessException(Model.EnumApiCode.SignWrong);
}
catch (Exception ex)
{
return Content("1");
}
}
- 再對修改後的test2 介面進行壓測,壓測結果如下:

| 介面 | tps | cpu佔用 | 壓測條件 |
|---|---|---|---|
| test1 | 10300左右 | 90% 左右 | 並發200,持續壓測 |
| test1 | 9200左右 | 91% 左右 | 並發200,持續壓測 |
進一步得到的結論是try catch 後性能有所提高,跟正常相比還有點點差距,全局過濾器對性能影響比較大,相當於走了管道,但是觀察程式碼test1 和test2程式碼還存在差距,懷疑test2 程式碼中new 了新異常導致性能差異,故再進一步進行程式碼修改求證
- 對test1 程式碼進行修改,修改後的程式碼如下:
/// <summary>
/// 正常返回數據介面1,但是先new 異常出來,保持跟上面test2 程式碼一致
/// </summary>
/// <returns></returns
[HttpGet("Test2")]
public async Task<IActionResult> Test2(string open)
{
var ex= new BusinessException(Model.EnumApiCode.SignWrong);
return Content("1");
}
- 對修改後的test1 程式碼進行壓測結果如下:

忘記截圖,大概和修改後的test2 程式碼壓測結果相差不大,大概tps 9300左右,故還是拿的上一個圖貼出來,諒解
| 介面 | tps | cpu佔用 | 壓測條件 |
|---|---|---|---|
| test1 | 9300左右 | 90%左右 | 並發200,持續壓測 |
| test2 | 9200左右 | 90%左右 | 並發200,持續壓測 |
進一步得到的結論是try catch 後性能和正常返回程式碼性能相當,相差無幾,可以忽略不計
2.2 最終結論
- 異常和正常程式碼性能旗鼓相當,但是全局過濾器對性能影響比較大,大概降低了60%左右,全局過濾器走了管道,但是這跟微軟官方的性能優化又有衝突,想必微軟官方也是出於對全局過濾器異常處理的考慮吧。
- 不使用全局過濾器進行業務自定義異常捕獲,最外層try catch 掉
- 對於非自定義異常,盡量按照微軟官方建議
- 使用 「測試者-執行者」模式
- 「嘗試-分析」模式
最後拋出一個待求證的問題
- 疑問一:大量拋出非自定義異常,性能和正常返回性能對比會如何?比如字元串轉換int 不使用TryParse 去轉換
以上結論個人壓測結果,如有不對,歡迎交流糾正
- 參考文獻
- //docs.microsoft.com/zh-cn/dotnet/standard/design-guidelines/exceptions-and-performance
- //docs.microsoft.com/zh-cn/aspnet/core/performance/performance-best-practices?view=aspnetcore-6.0#understand-hot-code-paths




