差距50倍!为什么Web API第一次执行这么慢?
前言
新建一個ASP.NET Core Web API項目,使用命令行方式啟動,連續發送多次請求。
從下圖的時間線可以發現,第一次執行(116ms)比后面的(2ms)慢了很多:
在這100多ms中,Web API到底做了些什么?!
示例代碼
為了更好定位Web API執行情況,示例Controller代碼如下:
[HttpGet] public?string?Get() {Thread.Sleep(10);var?now?=?DateTime.Now;while?((DateTime.Now?-?now).TotalMilliseconds?<?10){}var?result?=?HttpContext.TraceIdentifier;Thread.Sleep(10);return?result; }Thread.Sleep用于將框架代碼和業務執行代碼執行時間分開
while循環用于延長業務執行時間,方便找到業務代碼
PerfView
PerfView是一款免費的性能分析工具,可幫助排查CPU和內存相關的性能問題。
從https://github.com/Microsoft/perfview/releases下載最新版本PerfView并啟動。
配置
點擊主界面上的“Collect data machine wide”鏈接,打開收集數據窗口:
為了記錄所有操作,需要設置“CPU Sample Interval”為較小值(0.125)。
收集
使用命令行方式啟動Web API
點擊收集數據窗口的“Start Collection”按鈕
執行Web API請求
再點擊“Stop Collection”按鈕。
收集完成后,會生成.etl.zip文件:
雙擊“CPU Stacks”,會打開“Select Process Window”(選擇進程窗口),因為PerfView實際收集了所有進程的性能數據。
選擇Web API對應的進程,點擊“OK”按鈕。
火焰圖
在打開的窗口中選擇“Flame Graph”(火焰圖)選項卡,上方的“GroupPats”選擇“[group class entries] {%!}.%(=>class $1;{%!}::=>class $1”,可以看到如下效果:
火焰圖是用來展示CPU的調用棧的圖形:
y軸表示調用棧,每一層都是一個函數。調用棧越深,火焰就越高,頂部就是正在執行的函數,下方都是它的父函數。
x軸表示每個函數相對執行的時間長短。
speedscope
由于調用的函數較多,火焰圖并不能很清晰地反映。
這時,我們可以使用speedscope,一個交互式火焰圖可視化工具,幫助我們分析。
選擇菜單"File"->"Save View As",文件類型選擇“speed scope”。
打開網站https://www.speedscope.app/,將剛才保存的文件導入,效果如下圖:
頂部是線程列表,下面是所選線程對應的火焰圖,可以看到它的堆棧順序與PerfView相反,是從上到下的。
很容易定位到Web API執行的線程,因為可以看到Thread.Sleep留出的2段空白。
分析
圖中相同的顏色塊表示同一函數,我們只需要找到和業務代碼同一行顏色不同的位置,就表示處于不同方法調用中。
先看業務代碼執行前,從上往下看,很快就定位到一個運行時間較長的位置:
執行的是Http1Connection.TryParseRequest方法,耗時11.85ms,可見重用連接是非常有必要的。
下面是找到的部分耗時比較大的方法:
執行前
Microsoft.AspNetCore.Routing.Matching.DfaMatcherFactory.CreateMatcher - 22.73ms
Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker - 30.15ms
執行后
Microsoft.AspNetCore.Mvc.Formatters.TextOutputFormatter.WriteAsync - 5.79ms
結論
后面請求快的原因也可以解釋了,比如重用Http連接,方法內部緩存了結果(DfaMatcherFactory調用了DataSourceDependentCache),這也為提高我們自己程序的性能指明了思路。
PerfView + speedscope確實能夠幫助我們分析性能,理解代碼執行情況。你還不趕快安排上!
如果你覺得這篇文章對你有所啟發,請關注我的個人公眾號”My IO“,記住我!
總結
以上是生活随笔為你收集整理的差距50倍!为什么Web API第一次执行这么慢?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Blazor 路由及导航开发指南
- 下一篇: Docker小白到实战之开篇概述