案例研究:隔離效能問題(C#、Visual Basic、F#)
使用分析工具來調查效能問題,並隔離問題區域。 此案例研究會使用具有效能問題的範例應用程式來示範如何使用分析工具來提高效率。 如果您想要比較分析工具,請參閱 我應該選擇哪一個工具?
此案例研究涵蓋下列主題:
- 如何使用 Visual Studio 分析工具來分析應用程式效能。
- 如何解譯這些工具提供的數據,以識別效能瓶頸。
- 如何套用實際策略來優化程式代碼,著重於 .NET 計數器、呼叫計數和計時數據。
遵循這些技術,然後將這些技術套用至您自己的應用程式,使其更有效率且符合成本效益。
找出效能問題案例研究
此案例研究中的範例應用程式是一個 ASP.NET 應用程式,可對模擬資料庫執行查詢。 此範例是以 診斷範例為基礎。
範例應用程式的主要效能問題在於程式碼撰寫模式效率不佳。 應用程式存在一個性能瓶頸,明顯影響其效率。 問題包括下列徵兆:
低 CPU 使用量:應用程式會顯示低 CPU 使用量,表示 CPU 不是瓶頸。
高線程池線程計數:線程計數相對較高且穩步上升,顯示線程池可能面臨資源匱乏。
應用程式回應緩慢:應用程式因沒有可用的線程來處理新的工作專案而回應緩慢。
案例研究旨在藉由採用 Visual Studio 的分析工具來分析應用程式的效能來解決這些問題。 藉由瞭解應用程式效能的改善位置及方式,開發人員可以實作優化,讓程式代碼更快且更有效率。 最終目標是增強應用程序的整體效能,使其更有效率且符合成本效益來執行。
挑戰
解決範例 .NET 應用程式中的效能問題,會面臨數個挑戰。 這些挑戰源於診斷效能瓶頸的複雜性。 修正所描述問題的主要挑戰如下:
診斷效能瓶頸:其中一個主要挑戰是準確識別效能問題的根本原因。 低 CPU 使用量與效能緩慢相結合,可能會有多個因素。 開發人員必須使用分析工具有效地診斷這些問題,這需要了解這些工具的運作方式,以及如何解譯其輸出。
知識與資源限制:Teams 可能會面臨與知識、專業知識和資源相關的限制。 分析及優化應用程式需要特定的技能和經驗,並非所有小組都可以立即存取這些資源。
解決這些挑戰需要一種策略性方法,結合對分析工具、技術知識的有效使用,以及仔細的規劃和測試。 案例研究旨在引導開發人員完成此程式,提供策略和見解來克服這些挑戰並改善應用程式的效能。
策略
以下是此案例研究中方法的高階檢視:
- 我們會在收集效能數據時監看 .NET 計數器計量來開始調查。 如同 CPU 使用量工具,Visual Studio 的 .NET 計數器 工具也是效能調查的良好起點。
- 接下來,為獲得更多洞見以協助隔離問題或提升效能,請考慮使用其他分析工具之一來收集追蹤記錄。 例如,使用 Instrumentation 工具來查看呼叫計數和計時數據。
資料收集需要下列工作:
- 將應用程式設定為發行版本。
- 從效能分析工具中選取 .NET 計數器工具(Alt+F2)。 (後續步驟涉及檢測工具。
- 從效能分析器啟動應用程式並收集追蹤資料。
檢查性能計數器
執行應用程式時,我們會觀察 .NET 計數器工具中的計數器。 針對初始調查,一些要留意的重要計量包括:
-
CPU Usage
。 觀看此計數器以確定效能問題是否在高或低 CPU 使用率下發生。 這可以是特定效能問題的線索。 例如:- 使用高 CPU 使用量時,請使用 CPU 使用量工具來識別我們或許能夠將程式代碼優化的區域。 如需此教學的教程,請參閱 案例研究:給初學者的程式代碼優化指南。
- 使用低 CPU 使用量時,使用檢測工具來根據時鐘時間識別呼叫計數和平均函式時間。 這有助於識別諸如競爭或執行緒池飢餓等問題。
-
Allocation Rate
。 針對提供要求的 Web 應用程式,速率應該相當穩定。 -
GC Heap Size
。 請觀看此計數器,以查看記憶體使用量是否持續增加且可能流失。 如果看起來很高,請使用其中一個記憶體使用量工具。 -
Threadpool Thread Count
。 針對提供要求的 Web 應用程式,請觀看此計數器,以查看線程計數是否保持穩定或以穩定速率上升。
以下範例顯示 CPU Usage
低,而 ThreadPool Thread Count
相對較高。
低 CPU 使用量的穩步上升線程計數可能是線程集區饑餓的指標。 線程池被迫不斷生成新線程。 當集區沒有可用的線程來處理新的工作專案,而且通常會造成應用程式回應緩慢時,就會發生線程集區饑餓。
根據低 CPU 使用量和相對較多的執行緒數量,基於可能出現的執行緒池資源匱乏問題的理論,切換至使用分析工具。
調查通話計數和計時數據
讓我們看看檢測工具的追蹤,看看我們是否可以嘗試深入了解線程發生的情況。
使用檢測工具收集追蹤並將其載入Visual Studio之後,我們會先檢查初始 .diagsession 報表頁面,其中顯示摘要數據。 在收集的追蹤中,我們使用報表中的 [開啟詳細資料] 連結,然後選取 [火焰圖]。
Flame Graph 視覺效果顯示,QueryCustomerDB
函式(以黃色顯示)負責應用程式運行時間的很大一部分。
以滑鼠右鍵按兩下 QueryCustomerDB
函式,然後選擇 [呼叫樹狀結構] 中的 [檢視]。
應用程式中 CPU 使用量最高的程式代碼路徑稱為 熱路徑。 經常性路徑火焰圖示 ()可協助快速識別可能改善的效能問題。
在 [呼叫樹狀結構 檢視] 中,您可以看到熱門路徑包含 QueryCustomerDB
函式,這表明潛在的效能問題。
相對於其他函式所花費的時間,Self 和 QueryCustomerDB
函式的 Avg Self 值很高。 與 Total 和 Avg Total不同,Self 值會排除在其他函式中花費的時間,因此這是尋找效能瓶頸的好位置。
提示
如果 Self 值相對較低,而不是高值,您可能想要查看 QueryCustomerDB
函式所呼叫的實際查詢。
按兩下 QueryCustomerDB
函式以顯示函式的原始程式碼。
public ActionResult<string> QueryCustomerDB()
{
Customer c = QueryCustomerFromDbAsync("Dana").Result;
return "success:taskwait";
}
我們做了一些研究。 或者,我們可以節省時間,讓 科皮洛特 為我們做研究。
如果我們使用 Copilot,請從操作功能表中選取 [詢問 Copilot],然後輸入下列問題:
Can you identify a performance issue in the QueryCustomerDB method?
提示
您可以使用斜線命令來協助形成 Copilot 的良好問題,例如 /optimize。
Copilot 告訴我們,此程式代碼在不使用 await 的情況下呼叫異步 API。 這是 同步包覆異步 程式代碼模式,這是執行緒池耗盡的常見原因,而且可能會封鎖執行緒。
若要解決問題,請使用 await。 在此範例中,Copilot 會提供下列程式代碼建議以及說明。
public async Task<ActionResult<string>> QueryCustomerDB()
{
Customer c = await QueryCustomerFromDbAsync("Dana");
return "success:taskwait";
}
如果您看到與資料庫查詢相關的效能問題,您可以使用 Database 工具 來調查特定呼叫是否較慢。 此數據可能表示有機會優化查詢。 如需示範如何使用資料庫工具來調查效能問題的教學課程,請參閱 案例研究:將程式代碼優化的初學者指南。 資料庫工具支援 .NET Core,並且可以使用 ADO.NET 或 Entity Framework Core。
若要在 Visual Studio 中取得個別線程行為的視覺效果,您可以在偵錯時使用 平行堆疊 視窗。 此視窗會顯示個別線程、正在等待的線程、其所等待的線程,以及 死結的相關信息。
如需瞭解執行緒集區資源不足的其他資訊,請參閱 偵測執行緒集區資源不足。
後續步驟
下列文章和部落格文章提供詳細資訊,可協助您瞭解如何有效地使用 Visual Studio 效能工具。