总目录
前言
NET开发过程中,经常会使用Stopwatch 来测量方法的执行所需时间,以便了解代码的执行效率。这里介绍一个开源库:MethodTimer.Fody。它可以辅助我们更为方便快速的完成方法执行效率的测量。
一、MethodTimer.Fody 是什么?
- 主页:https://github.com/Fody/MethodTimer
- MethodTimer.Fody 是一个功能强大的库,可以用于测量 .NET 应用程序中的方法的执行时间。允许你在不修改代码的情况下,自动地测量和记录方法的执行时间。
- 这个工具是基于.NET的 weaving 技术,通过修改IL(Intermediate Language,中间语言)代码来插入计时逻辑,从而在方法调用前后记录时间戳,进而计算出方法的执行时间。
- 它使用 Fody 插件框架可以无缝集成到项目中,所以向代码中添加性能测量功能变得非常容易。
二、使用 MethodTimer.Fody
1. 安装与配置
1 安装 MethodTimer.Fody 程序包
2 引用该程序包后,重新生成项目,一般会在项目目录下会生成一个FodyWeavers.xml
文件,内容如下:
xml
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<MethodTimer />
</Weavers>
- 如果目录下生成FodyWeavers.xml文件,则在vs编辑器中显示所有文件,然后将FodyWeavers.xml文件 包括在项目中
- 如目录下没生成FodyWeavers.xml文件,则自己新建一个FodyWeavers.xml文件,添加上面的代码即可
2. 使用
1. 指定方法计时
- 给需要计时的方法添加
[Time]
特性即可
csharp
internal class Program
{
static void Main(string[] args)
{
new Program().SayHi();
Console.WriteLine("测试方法执行结束");
Console.ReadKey();
}
[Time]
public void SayHi()
{
Console.WriteLine("Hi");
}
}
- 运行结果
2. 类中所有方法计时
- 将
[Time]
特性添加在Class
上
csharp
[Time]
internal class Program
{
static void Main(string[] args)
{
new Program().SayHi();
new Program().SayGoodBye();
Console.WriteLine("测试方法执行结束");
Console.ReadKey();
}
public void SayHi()
{
Console.WriteLine("Hi");
}
public void SayGoodBye()
{
Console.WriteLine("GoodBye");
}
}
- 运行结果
3. 原理分析
- 当我们给以下代码添加上特性
csharp
[Time]
internal class Program
{
static void Main(string[] args)
{
new Program().SayHi();
new Program().SayGoodBye();
Console.WriteLine("测试方法执行结束");
Console.ReadKey();
}
public void SayHi()
{
Console.WriteLine("Hi");
}
public void SayGoodBye()
{
Console.WriteLine("GoodBye");
}
}
- 在Main 方法的第一行打断点然后F11逐语句调试,会发现会自动生成以下代码
csharp
internal class Program
{
private static void Main(string[] args)
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
new Program().SayHi();
new Program().SayGoodBye();
Console.WriteLine("测试方法执行结束");
Console.ReadKey();
}
finally
{
stopwatch.Stop();
Trace.WriteLine("Program.Main " + stopwatch.ElapsedMilliseconds + "ms");
}
}
public void SayHi()
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
Console.WriteLine("Hi");
}
finally
{
stopwatch.Stop();
Trace.WriteLine("Program.SayHi " + stopwatch.ElapsedMilliseconds + "ms");
}
}
public void SayGoodBye()
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
Console.WriteLine("GoodBye");
}
finally
{
stopwatch.Stop();
Trace.WriteLine("Program.SayGoodBye " + stopwatch.ElapsedMilliseconds + "ms");
}
}
}
当我们添加上了Time
特性会自动的生成 Stopwatch
相关的代码 对 方法进行计时,并且将测量信息通过Trace.WriteLine
输出
二、自定义测量信息的输出
在上面的示例中我们发现,如果只是添加[Time]
特性,计时信息只会在编辑器的【输出】窗口中进行打印输出,如果我们想要在控制台,或者在日志中输出该如何操作呢?
那么我们只需要定义一个静态类即可:
csharp
public static class MethodTimeLogger
{
//按时段输出
public static void Log(MethodBase methodBase, TimeSpan elapsed, string message)
{
Console.WriteLine($"方法:{methodBase.Name} 耗时(时段):{elapsed}, 信息:{message}");
}
//按总毫秒数输出
//public static void Log(MethodBase methodBase, long milliseconds, string message)
//{
// Console.WriteLine($"方法:{methodBase.Name} 耗时(总毫秒数):{milliseconds}, 信息:{message}");
//}
}
-
MethodTimeLogger
是MethodTimer.Fody 定义好的切入逻辑,不用去改动,只需要改动逻辑 Log 方法内的输出内容即可。- 不要改动
MethodTimeLogger
这个类的名称 - 不要改动Log 这个方法的名称
- 自定义的内容卸载Log方法中即可。
- 不要改动
-
如果改动Log方法名称,会有报错信息
1. 使用MethodTimeLogger
具体示例:
csharp
[Time]
internal class Program
{
static void Main(string[] args)
{
new Program().SayHi();
new Program().SayGoodBye();
Console.WriteLine("测试方法执行结束");
Console.ReadKey();
}
public void SayHi()
{
Console.WriteLine("Hi");
}
public void SayGoodBye()
{
Console.WriteLine("GoodBye");
}
}
public static class MethodTimeLogger
{
//按时段输出
public static void Log(MethodBase methodBase, TimeSpan elapsed, string message)
{
Console.WriteLine($"方法:{methodBase.Name} 耗时(时段):{elapsed}, 信息:{message}");
}
//按总毫秒数输出
//public static void Log(MethodBase methodBase, long milliseconds, string message)
//{
// Console.WriteLine($"方法:{methodBase.Name} 耗时(总毫秒数):{milliseconds}, 信息:{message}");
//}
}
}
当我们定义了MethodTimeLogger
这个静态类的时候,会自动生成如下代码
csharp
internal class Program
{
private static void Main(string[] args)
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
new Program().SayHi();
new Program().SayGoodBye();
Console.WriteLine("测试方法执行结束");
Console.ReadKey();
}
finally
{
stopwatch.Stop();
string message = default(string);
MethodTimeLogger.Log(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(Program).TypeHandle), stopwatch.Elapsed, message);
}
}
public void SayHi()
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
Console.WriteLine("Hi");
}
finally
{
stopwatch.Stop();
string message = default(string);
MethodTimeLogger.Log(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(Program).TypeHandle), stopwatch.Elapsed, message);
}
}
public void SayGoodBye()
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
Console.WriteLine("GoodBye");
}
finally
{
stopwatch.Stop();
string message = default(string);
MethodTimeLogger.Log(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(Program).TypeHandle), stopwatch.Elapsed, message);
}
}
}
运行结果如下:
2. 其他
当我们需要传入相关信息的时候,可以使用如下:
csharp
internal class Program
{
static void Main(string[] args)
{
new Program().SayHi();
Console.WriteLine("测试方法执行结束");
Console.ReadKey();
}
[Time("计时测量")]
public void SayHi()
{
Console.WriteLine("Hi");
}
}
public static class MethodTimeLogger
{
//按时段输出
public static void Log(MethodBase methodBase, TimeSpan elapsed, string message)
{
Console.WriteLine($"方法:{methodBase.Name} 耗时(时段):{elapsed}, 信息:{message}");
}
}
运行结果:
结语
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。