当前位置: 首页 > article >正文

C# MethodTimer.Fody 使用详解

总目录


前言

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


http://www.kler.cn/a/401737.html

相关文章:

  • 面向服务的软件工程——巨详细讲解商务流程建模符号 (BPMN),一篇章带你入门BPMN!!!(week1)
  • FromData格式提交接口时入参被转成JSON格式问题
  • Python | Leetcode Python题解之第564题数组嵌套
  • ChatGPT学术专用版,一键润色纠错+中英互译+批量翻译PDF
  • ATmaga8单片机Pt100温度计源程序+Proteus仿真设计
  • 【C语言】科技要闻。
  • ubuntu固定ip
  • AI图片分析接口LiteAIServer摄像机实时接入分析平台车辆检测算法
  • 从源头保障电力安全:输电线路动态增容与温度监测技术详解
  • Linux第93步_Linux内核的LED灯驱动
  • 甲骨文云服务器 (Oracle Cloud) 终极防封、防回收的教程!
  • 【鸿蒙开发】第十三章 ArkTS基础类库-容器(数据结构)
  • 用pandoc工具实现ipynb,md,word,pdf之间的转化
  • Vue3 -- 搭建项目路由【vue-router!!!】
  • Qt 文件管理
  • 网络编程-002-UDP通信
  • vscode使用ssh配置docker容器环境
  • Unity类银河战士恶魔城学习总结(P128 Switch UI with KeyBoard用键盘切换UI)
  • 【QT实战】加解密文件夹之————应用程序获取管理员权限
  • 365天深度学习训练营-第P5周:Pytorch实现运动鞋识别
  • 【STM32】在 STM32 USB 设备库添加新的设备类
  • 使用 helm 部署 gitlab
  • 投资策略规划最优决策分析
  • c++实现B树(下)
  • 【论文笔记】Towards Privacy-Aware Sign Language Translation at Scale
  • 手摸手5-springboot开启打印sql完整语句