为什么要使用MiniProfiler?
如果程序需要性能调优,我们使用它可以帮我们分析代码的执行情况。
MiniProfiler是一款性能分析的小程序。
可以对一个页面本身,及该页面通过直接引用、Ajax、Iframe形式访问的其它页面进行监控。
监控内容包括数据库访问,网络请求等,并可以显示数据库访问的SQL,以及网络请求的地址等。
最后以很友好的方式展现在页面上。
我们先以Console程序为例,使用MiniProfiler小工具。
1. 安装包:MiniProfiler
2. 创建一个profiler对象
//profiler和MiniProfiler.Current是相等的
var profiler = MiniProfiler.StartNew("My Pofiler Name");
3. 创建一个Step,作为一个记录单元
using (profiler.Step("CallDataBase")){ ... }
4. 对于数据库的操作,ADO.NET里面里面的对象,需要使用ProfiledXXX类包装一下:
DbConnection cnn = new SqlConnection(@"...");
cnn = new ProfiledDbConnection(cnn, profiler);
DbCommand dbCommand = new SqlCommand("SELECT name FROM [ActionType_lkp]");
dbCommand = new ProfiledDbCommand(dbCommand, cnn, profiler);
5. 对于网络请求,需要使用CustomTiming方法,把网络请求的地址输入,后面在分析性能的时候,可以友好的展示出来:
using (var wc = new WebClient())
using (profiler.CustomTiming("https", "GET https://www.baidu.com"))
{
wc.DownloadString("https://www.baidu.com");
}
6. Step可以嵌套Step:
using (profiler.Step("outer"))
{
System.Threading.Tasks.Parallel.For(0, 5, i =>
{
doWork();
using (profiler.Step("step " + i))
{
doWork();
using (profiler.Step("sub-step" + i))
{
doWork();
}
}
});
}
7. 在最后代码的结尾位置,停止profiler
profiler.Stop();
8. 打出出来结果:
Console.WriteLine(profiler.RenderPlainText());
我们使用MiniProfiler对Asp.Net MVC应用程序进行性能分析,基本思路和Console程序是一样的。
1. 安装包:MiniProfiler.Mvc5
2. 注册全局的Filters,并对视图引擎进行Profilling包装,还可以对MiniProfiler全局配置,这些内容应该放在,应用程序启动的时候:
protected void Application_Start()
{
...
//NO.1
GlobalFilters.Filters.Add(new ProfilingActionFilter());
//NO.2
var copy = ViewEngines.Engines.ToList();
ViewEngines.Engines.Clear();
foreach (var item in copy)
{
ViewEngines.Engines.Add(new ProfilingViewEngine(item));
}
//NO.3
MiniProfiler.Configure(new MiniProfilerOptions
{
// Different RDBMS have different ways of declaring sql parameters - SQLite can understand inline sql parameters just fine.
// By default, sql parameters will be displayed.
//SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter(),
// These settings are optional and all have defaults, any matching setting specified in .RenderIncludes() will
// override the application-wide defaults specified here, for example if you had both:
// PopupRenderPosition = RenderPosition.Right;
// and in the page:
// @MiniProfiler.Current.RenderIncludes(position: RenderPosition.Left)
// ...then the position would be on the left on that page, and on the right (the application default) for anywhere that doesn't
// specified position in the .RenderIncludes() call.
PopupRenderPosition = RenderPosition.Right, // defaults to left
PopupMaxTracesToShow = 10, // defaults to 15
// ResultsAuthorize (optional - open to all by default):
// because profiler results can contain sensitive data (e.g. sql queries with parameter values displayed), we
// can define a function that will authorize clients to see the JSON or full page results.
// we use it on http://stackoverflow.com to check that the request cookies belong to a valid developer.
ResultsAuthorize = request => request.IsLocal,
// ResultsListAuthorize (optional - open to all by default)
// the list of all sessions in the store is restricted by default, you must return true to allow it
ResultsListAuthorize = request =>
{
// you may implement this if you need to restrict visibility of profiling lists on a per request basis
return true; // all requests are legit in this example
},
// Stack trace settings
StackMaxLength = 256, // default is 120 characters
// (Optional) You can disable "Connection Open()", "Connection Close()" (and async variant) tracking.
// (defaults to true, and connection opening/closing is tracked)
TrackConnectionOpenClose = true
});
}
3. 在每一个请求的开始的时候,应该开始一个profiler:
protected void Application_BeginRequest()
{
//NO.4
// You can decide whether to profile here, or it can be done in ActionFilters, etc.
// We're doing it here so profiling happens ASAP to account for as much time as possible.
if (Request.IsLocal) // Example of conditional profiling, you could just call MiniProfiler.StartNew();
{
MiniProfiler.StartNew();
}
}
4. 在请求结束的时候,应该停止profiler:
protected void Application_EndRequest()
{
//NO.5
MiniProfiler.Current?.Stop(); // Be sure to stop the profiler!
}
5. 在web.config文件中编辑
<system.webServer>
...
<handlers>
<!--NO.6-->
<add name="MiniProfiler" path="mini-profiler-resources/*" verb="*"
type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified"
preCondition="integratedMode" />
</handlers>
</system.webServer>
6. 在html页面的</body>之前添加:
@StackExchange.Profiling.MiniProfiler.Current.RenderIncludes();
7. 浏览器访问某页面,在页面的右上角有一个加载时间:
8. 点击时间,可以打开独立的profiler页面:
通过上面的截图,我们可以看到:
a. 访问页面的URL
b. 服务器的名称
c. 页面加载的总时间
d. 代码执行栈的每一步花费的时间
e. 代码执行是否包含数据库访问和网络请求
f. 浏览器视角花费的时间,包括请求,响应,DOM加载,Paint等等
g. 对于数据库的访问,有更多细节,包括sql语句是什么
h. 对于网络请求的访问,可以知道,请求是什么类型的,网络地址是什么
通过这些信息可以帮我们定位出那些步骤执行时间较长,我们就可以进一步对其进行性能分析和优化。