在上一篇介紹了 ASP.NET Core Task block 檢測器 - Ben.BlockingDetector ,可以在 ASP.NET Runtime 時偵測 task block 的情境並透過 log 輸出,但預防的工作總是希望越早進行越好,越快發現就更早的預防不好的寫法及早修改,本篇要介紹的是非同步代碼分析套件,可以分析靜態代碼中可能用法"不正確"的代碼,可以若有問題或是錯誤的地方歡迎高手大大給予指導或討論。
開啟 Visual Studio 的 Nuget 搜尋 Microsoft.VisualStudio.Threading.Analyzers 找到後下載
或是可以透過 Nuget Package Console 輸入下列指令
Install-Package Microsoft.VisualStudio.Threading.Analyzers -Version 16.3.52安裝完畢之後到專案檔底下確認是否有安裝成功
<ItemGroup> <PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="16.3.52" /> </ItemGroup>
分析指南
在安裝完後會針對目前專案靜態代碼進行分析,主要目的是透過此套件來檢查有關 Threads 和非同步的常見錯誤或是潛在問題,從官方 Github 說明頁面可以得知分析項目有包含以下內容
並且在規則中有分嚴重程度,且根據分析工具抓到靜態代碼的內容來給於提示與建議,嚴重性分為三類
加入範例代碼
透過上述了解了規則之後,接下來我們加入 Thread blocking 的代碼來簡單示範分析結果,在新增的專案 controller 類別加入常見的 Task.Result 與 Task.Wait 阻塞方法
public class ValuesController : ControllerBase { // GET api/values [HttpGet] public async void Get() { var result = await Task.Run(() => BlockingTask()); } private static int BlockingTask() { // Detected blocking return MethodAsync().Result; } private static async Task<int> MethodAsync() { await Task.Delay(1000); return 5; } //private static object _lock; [HttpGet("/")] public Task Slower() { // Detected blocking in called method return DoSomethingAsync(); } private async Task DoSomethingAsync() { await Task.Delay(1000); // Detected blocking Task.Run(() => { Thread.Sleep(1000); }).Wait(); } [HttpGet("/hello")] public string Hello() { // Not detected: Thread.Sleep happens at OS level Thread.Sleep(2000); return "Hello World"; } [HttpGet("/hello-sync-over-async")] public string HelloSyncOverAsync() { // Detected blocking Task.Delay(2000).Wait(); return "Hello World"; } [HttpGet("/hello-async-over-sync")] public async Task<string> HelloAsyncOverSync() { // Detected blocking in called method var result = await Task.Run(() => BlockingTask()); return $"Hello World {result}"; } [HttpGet("/hello-async")] public async Task<string> HelloAsync() { // No blocking :) await Task.Delay(2000); return "Hello World"; } [HttpGet("/hello-async-precompleted")] public async Task<string> HelloAsyncPrecompleted() { Task<int> task = MethodAsync(); if (!task.IsCompletedSuccessfully) { // Await completes the Task without blocking await task; } // The task is completed at this point so .Result doesn't trigger blocking var result = task.Result; return $"Hello World {result}"; } }
分析建議
在安裝完套件之後,可以看到原本看似 peace 的靜態代碼在分析之後有潛在的風險,舉例來說用到 Task.Result ,就會說明目前寫法可能會造成 deadlock,建議改用 await 方式避免
或是使用 Task.Wait
或是方法也會有相關建議
透過此套件可以提早發現代碼中可能造成的問題,避免上線後才發現影響到用戶,在 Github 網頁有更詳細的介紹與說明,若有興趣了解細節運作可以查看其 Github source code : 傳送門,希望這篇文章有幫助到大家&喜歡 :)
0 意見:
張貼留言