C# 开发技巧 轻松监控方法执行耗时
<h2>前言</h2><p><span data-spm-anchor-id="5176.28103460.0.i15.297c3da2KDVzYe">MethodTimer.Fody 是一个功能强大的库,可以用于测量 .NET 应用程序中的方法的执行时间。允许你在不修改代码的情况下,自动地测量和记录方法的执行时间。</span></p>
<p><span data-spm-anchor-id="5176.28103460.0.i15.297c3da2KDVzYe">这个工具是基于.NET的 weaving 技术,通过修改IL(Intermediate Language,中间语言)代码来插入计时逻辑,从而在方法调用前后记录时间戳,进而计算出方法的执行时间。</span></p>
<p>它使用 Fody 插件框架可以无缝集成到项目中,所以向代码中添加性能测量功能变得非常容易。</p>
<h2>使用方法</h2>
<h3>1、安装NuGet包</h3>
<p>在Visual Studio中,打开NuGet包管理器,搜索并安装<code>MethodTimer.Fody或者使用命令方式</code></p>
<div class="cnblogs_code">
<pre>PM> Install-<span style="color: rgba(0, 0, 0, 1)">Package Fody
PM</span>> Install-Package MethodTimer.Fody</pre>
</div>
<p>具体操作如下图所示:</p>
<p><img src="https://img2024.cnblogs.com/blog/576536/202407/576536-20240722223736231-1289921903.png" alt="" width="771" height="442" loading="lazy" style="display: block; margin-left: auto; margin-right: auto"></p>
<h3><span data-spm-anchor-id="5176.28103460.0.i19.297c3da2KDVzYe">2、使用 Time 特性</span></h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> MethodTimer;
</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> DemoConsole
{
</span><span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Program
{
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 程序入口
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="args"></param></span>
<span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Main(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] args)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 调用示例方法</span>
<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Program().DoSomething();
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">测试方法执行结束!!!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ReadKey();
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 示例方法
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 0, 1)">
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> DoSomething()
{
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">测试方法执行时间!!!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
}</span></pre>
</div>
<p><span data-spm-anchor-id="5176.28103460.0.i19.297c3da2KDVzYe">Fody是一个.NET的weaving框架,需要确保项目已经启用了Fody,并且在项目属性的"Fody"标签页中添加了<code>MethodTimer</code>模块。</span></p>
<h3>3、执行效果</h3>
<p>启动运行程序,可以在输出窗口查看方法的执行耗时,具体如下图所示:</p>
<p><img src="https://img2024.cnblogs.com/blog/576536/202407/576536-20240722225121847-419506948.png" alt="" width="732" height="645" loading="lazy" style="display: block; margin-left: auto; margin-right: auto"></p>
<h3>4、其他说明</h3>
<p>Time 特性不仅可以加在方法上还可以直接添加到 Class 上,具体如下代码所示:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> MethodTimer;
</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> ConsoleApp3
{
</span><span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Program
{
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 程序入口
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="args"></param></span>
<span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Main(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] args)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 调用示例方法</span>
<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Program().DoSomething();
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Program().ToDoSomething();
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">方法执行结束!!!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ReadKey();
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 示例方法1
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> DoSomething()
{
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">001——测试执行时间方法!!!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 示例方法2
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> ToDoSomething()
{
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">002——测试执行时间方法!!!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
}</span></pre>
</div>
<p>运行程序后,可以输出类中每个方法的执行时间。</p>
<p><img src="https://img2024.cnblogs.com/blog/576536/202407/576536-20240722225808889-364075174.png" alt="" width="884" height="665" loading="lazy" style="display: block; margin-left: auto; margin-right: auto"></p>
<p>实际上,在代码中添加了 Time 特性以后,Fody 会自动生成下面的代码</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MyClass
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> DoSomething()
{
Stopwatch stopwatch </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Stopwatch();
stopwatch.Start();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 原始方法体</span>
System.Threading.Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">1000</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 模拟工作</span>
<span style="color: rgba(0, 0, 0, 1)">
stopwatch.Stop();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 输出或记录执行时间</span>
Console.WriteLine($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">执行时间:{stopwatch.Elapsed.TotalMilliseconds} ms</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}</span></pre>
</div>
<h3>5、拦截记录</h3>
<p>如果想手动处理日志记录,可以定义一个静态类来拦截日志记录,方法的示例,具体如下代码所示</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MethodTimeLogger
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Log(MethodBase methodBase, TimeSpan elapsed, <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> message)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Do some logging here</span>
<span style="color: rgba(0, 0, 0, 1)"> }
}</span></pre>
</div>
<p>生成后的代码</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MyClass
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> MyMethod()
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> stopwatch =<span style="color: rgba(0, 0, 0, 1)"> Stopwatch.StartNew();
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{</span>
Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)">
{
stopwatch.Stop();
MethodTimeLogger.Log(methodof(MyClass.MyMethod), stopwatch.Elapsed);
}
}
}</span></pre>
</div>
<p>MethodTimer.Fody是一个非常有用的工具,尤其在性能调优阶段,可以帮助你快速识别出哪些方法是性能瓶颈,从而针对性地进行优化。</p>
<h2>主要特点</h2>
<p>1、非侵入式</p>
<p>MethodTimer.Fody不需要在源代码中添加额外的计时代码,只需要在项目中添加相应的NuGet包,并在项目属性中做一些配置,就可以自动地为方法添加计时功能。</p>
<p>2、灵活的配置</p>
<p>你可以选择性地对某些方法进行计时,或者排除不想被计时的方法。这通常通过方法的特性或者类的命名空间来进行配置。</p>
<p>3、输出结果多样化</p>
<p>MethodTimer.Fody可以将计时结果输出到不同的地方,如控制台、日志文件或者通过事件追踪(ETW)等方式,这取决于你的配置。</p>
<p>4、性能影响小</p>
<p>尽管MethodTimer.Fody在方法中插入了计时逻辑,但它被设计得尽可能地对性能影响最小,通过精心优化的IL代码插入策略来实现这一点。</p>
<h2>总结</h2>
<p data-tool="mdnice编辑器">MethodTimer.Fody 是一个强大的工具,提供了简便的方式来监控 C# 方法的执行时间,特别适用于需要快速诊断性能问题的场合。</p>
<p data-tool="mdnice编辑器">通过其灵活的配置和非侵入性的特性,它可以无缝地融入现有的开发流程中,帮助我们团队提高应用的性能和响应速度。</p>
<p data-tool="mdnice编辑器">这个工具特别适合在开发和测试阶段快速识别性能瓶颈,而无需在代码中显式地添加计时代码,可以保持源代码的整齐性和可维护性。</p>
<h2>开源地址</h2>
<p>https://github.com/Fody/MethodTimer</p>
<p> </p>
<p style="text-align: left" data-tool="mdnice编辑器">如果觉得这篇文章对你有用,欢迎加入微信公众号 [<strong>DotNet技术匠</strong>] 社区,与其他热爱技术的同行交流心得,共同成长。</p>
<p data-tool="mdnice编辑器"><img src="https://img2024.cnblogs.com/blog/576536/202407/576536-20240722093332651-213039456.png" alt="" style="display: block; margin-left: auto; margin-right: auto"></p><br><br>
来源:https://www.cnblogs.com/1312mn/p/18317245
頁:
[1]