总目录
前言
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
文件,内容如下:
<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]
特性即可
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
上
[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. 原理分析
- 当我们给以下代码添加上特性
[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逐语句调试,会发现会自动生成以下代码
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]
特性,计时信息只会在编辑器的【输出】窗口中进行打印输出,如果我们想要在控制台,或者在日志中输出该如何操作呢?
那么我们只需要定义一个静态类即可:
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
具体示例:
[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
这个静态类的时候,会自动生成如下代码
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. 其他
当我们需要传入相关信息的时候,可以使用如下:
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}");}}
运行结果:
结语
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。
参考资料:
MethodTimer.Fody 统计代码执行时间
C#测试开源运行耗时库MethodTimer.Fody