• C# 监测每个方法的执行次数和占用时间(测试4)


      今天也要做这个功能,就百度一下,结果搜索到了自己的文章。一开始还没注意,当看到里面的一个注释的方法时,一开始还以为自己复制错了代码,结果仔细一看网页的文章,我去,原来是自己写的,写的确实不咋地。

    把自己的文章的代码复制了下来,稍微改了一下,运行看了一下效果,然后仔细一看,计算的总时间不对,如下图:

    上一篇文章的地址:https://www.cnblogs.com/guxingy/p/10142242.html

    改了几个地方:

        /// <summary>
        /// 拦截器
        /// </summary>
        public class CallingLogInterceptor : IInterceptor
        {
            private DateTime dt { get; set; }
            private TimeSpan ts { get; set; }
    
            /// <summary>
            /// 方法执行前
            /// </summary>
            /// <param name="invocation"></param>
            private void PreProceed(IInvocation invocation)
            {
                dt = DateTime.Now;
            }
    
            /// <summary>
            /// 方法执行后
            /// </summary>
            /// <param name="invocation"></param>
            private void PostProceed(IInvocation invocation)
            {
                ts = DateTime.Now - dt;
    
    
                Console.WriteLine($"方法名称:{invocation.Method.Name}" );
                Console.WriteLine($"开始时间:{dt.ToString("yyyy-MM-dd HH:mm:ss fff")}");
                Console.WriteLine($"结束时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
                Console.WriteLine($"所用时间:{ts.TotalSeconds}");
    
    
                MethodOperationInfo.Add(invocation, ts.TotalMilliseconds);
            }
    
            /// <summary>
            /// 拦截
            /// </summary>
            /// <param name="invocation"></param>
            public void Intercept(IInvocation invocation)
            {
                this.PreProceed(invocation);
                invocation.Proceed();//调用
                this.PostProceed(invocation);
            }
        }
    View Code
        /// <summary>
        /// 测试类1
        /// </summary>
        public class Class5_test1
        {
            public virtual void test1()
            {
                test4();            
                test3();
                test2();
            }
            public virtual void test2()
            {
                System.Threading.Thread.Sleep(1000);
            }
            public virtual void test3()
            {
                System.Threading.Thread.Sleep(2000);
            }
            public virtual void test4()
            {
                System.Threading.Thread.Sleep(3000);
            }
        }
    View Code
        public class MyProxyGenerator
        {
            /// <summary>
            /// 创建一个代理对象
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <returns></returns>
            public static T CreateProxy<T>() where T : class
            {
                ProxyGenerator generator = new ProxyGenerator();//代理
                CallingLogInterceptor interceptor = new CallingLogInterceptor();//定义 拦截器
                T entity = generator.CreateClassProxy<T>(interceptor);
                return entity;
            }
        }
    View Code
        public class Class2
        {
            public static void test1()
            {
                Class5_test1 entity = MyProxyGenerator.CreateProxy<Class5_test1>();
                entity.test1();
                MethodOperationInfo.ShowContainsDetail();
    
                Console.Read();
            }
        }
    View Code

    说明:所有的测试,只是修改了一下Class5_test1 这个类给

    测试1

        /// <summary>
        /// 测试类1
        /// </summary>
        public class Class5_test1
        {
            public virtual void test1()
            {            
                test2();
                test3();
                test4();
            }
            public virtual void test2()
            {
                System.Threading.Thread.Sleep(1000);
            }
            public virtual void test3()
            {
                System.Threading.Thread.Sleep(2000);
            }
            public virtual void test4()
            {
                System.Threading.Thread.Sleep(3000);
            }
        }
    View Code

    问题:这里test1调用了test2、test3、test4,那么执行test1所用时间,应该是test2、test3、test4所用时间的总和,正确所用时间至少应该是6秒(1+2+3),结果这里输出的是3秒多,肯定不对。

    测试2

        /// <summary>
        /// 测试类1
        /// </summary>
        public class Class5_test1
        {
            public virtual void test1()
            {
                test4();
                test3();            
                test2();
            }
            public virtual void test2()
            {
                System.Threading.Thread.Sleep(1000);
            }
            public virtual void test3()
            {
                System.Threading.Thread.Sleep(2000);
            }
            public virtual void test4()
            {
                System.Threading.Thread.Sleep(3000);
            }
        }
    View Code

    问题:这里的test1方法的所用时间是1秒多,更不对了。

    结论:

      测试1 和 测试2 的区别,只是在test1里面改变了test2、test3、test4的执行顺序,结果时间却迥然不同,更奇怪的是,test1的所用时间,更是莫名的接近调用的倒数第二个方法。

      测试1里面,test1的所用时间,很接近test4。

      测试2里面,test1的所用时间,很接近test2。

      反正就是所用时间,很接近 方法体里面 最后一个 调用的方法,原因找到了再补充,了解一下动态代理的原理或许就知道了,也获取是自己写错了,估计是第一种可能

    乘着自己好奇,又测试了一下,看下面哦

        /// <summary>
        /// 测试类1
        /// </summary>
        public class Class5_test1
        {
            public virtual void test1()
            {
                Console.WriteLine("开始执行test1");
                test4();
                test3();            
                test2();
                Console.WriteLine("执行完成test1");
            }
            public virtual void test2()
            {
                System.Threading.Thread.Sleep(1000);
            }
            public virtual void test3()
            {
                System.Threading.Thread.Sleep(2000);
            }
            public virtual void test4()
            {
                System.Threading.Thread.Sleep(3000);
            }
        }
    View Code

    主要是是在,test1方法里面添加了方法的执行情况, 输出 开始执行 和 执行完成。

    找到原因了:拦截器对象只创建了一个,所以dt一直都是最后调用的那个方法的开始时间

          还是自己写的代码有问题啊

    赋上 改好的全部代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    
    
    using Castle.Core.Interceptor;
    using Castle.DynamicProxy;
    using System.Reflection;
    using Newtonsoft.Json;
    using System.Security.Cryptography;
    
    namespace ConsoleApplication3
    {
        //原文:https://www.cnblogs.com/guxingy/p/10142242.html
    
        public class Class2
        {
            public static void test1()
            {
                Class5_test1 entity = MyProxyGenerator.CreateProxy<Class5_test1>();
                entity.test1();
                MethodOperationInfo.ShowContainsDetail();
            }
        }
    
    
    
        public class MyProxyGenerator
        {
            /// <summary>
            /// 创建一个代理对象
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <returns></returns>
            public static T CreateProxy<T>() where T : class
            {
                ProxyGenerator generator = new ProxyGenerator();//代理
                CallingLogInterceptor interceptor = new CallingLogInterceptor();//定义 拦截器
                T entity = generator.CreateClassProxy<T>(interceptor);
                return entity;
            }
        }
    
    
    
    
        /// <summary>
        /// 拦截器
        /// </summary>
        public class CallingLogInterceptor : IInterceptor
        {
            private DateTime dt { get; set; }
            private TimeSpan ts { get; set; }
    
    
            /// <summary>
            /// 方法执行前
            /// </summary>
            /// <param name="invocation"></param>
            private void PreProceed(IInvocation invocation)
            {
                //创建一个唯一的标识
                //创建一个对象,并记录开始时间
    
                //dt = DateTime.Now;
                //Console.WriteLine($"开始执行,方法名称:{invocation.Method.Name},开始时间:{dt.ToString("yyyy-MM-dd HH:mm:ss fff")}");
                //Console.WriteLine();
    
                MethodOperationInfo.SetStartTime(invocation);
            }
    
            /// <summary>
            /// 方法执行后
            /// </summary>
            /// <param name="invocation"></param>
            private void PostProceed(IInvocation invocation)
            {
                //通用标识找到之前创建的那个对象,并记录结束时间
                
                //ts = DateTime.Now - dt;
                //Console.WriteLine($"执行完成,方法名称:{invocation.Method.Name}");
                //Console.WriteLine($"    开始时间:{dt.ToString("yyyy-MM-dd HH:mm:ss fff")}");
                //Console.WriteLine($"    结束时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
                //Console.WriteLine($"    所用时间:{ts.TotalSeconds}");
                //Console.WriteLine();
                
                MethodOperationInfo.SetEndTime(invocation);
            }
    
            /// <summary>
            /// 拦截
            /// </summary>
            /// <param name="invocation"></param>
            public void Intercept(IInvocation invocation)
            {
                this.PreProceed(invocation);
                invocation.Proceed();//调用
                this.PostProceed(invocation);
            }
        }
    
    
        
        /// <summary>
        /// 扩展
        /// </summary>
        public static class IntExtension
        {
            public static string ToString(this object obj, int len, bool afterFill = true)
            {
                string name = obj.ToString();
                //int count = len - name.Length;//不能用这个 汉字和英文占用的长度不同
                int count = len - System.Text.Encoding.Default.GetBytes(name).Length;
    
                if (afterFill)
                {
                    for (int i = 0; i < count; i++)
                    {
                        name += " ";
                    }
                    return name;
    
                }
                else
                {
                    string value = "";
                    for (int i = 0; i < count; i++)
                    {
                        value += " ";
                    }
                    value += name;
                    return value;
                }
            }
        }
    
    
    
        /// <summary>
        /// 操作日志
        /// </summary>
        public class MethodOperationInfo
        {
            public string NameSpaceName { get; set; }
            public string ClassName { get; set; }
            public string MethodName { get; set; }
            public string Parameters { get; set; }
            public string ParameterTypes { get; set; }
            public double TotalMilliseconds { get; set; }
    
    
            public string Name { get; set; }
            public DateTime StartTime { get; set; }
            public DateTime EndTime { get; set; }
            public bool IsEnd { get; set; }//标识这个对象是否完成计算耗时
            
            
    
    
    
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="invocation"></param>
            public MethodOperationInfo(IInvocation invocation)
            {
                StartTime = DateTime.Now;
                NameSpaceName = invocation.TargetType.Namespace;
                ClassName = invocation.TargetType.Name;
                MethodName = invocation.Method.Name;//方法名
                ParameterTypes = GetParameterTypes(invocation);//参数类型
                Parameters = GetParameter(invocation);//参数
                Name = GetName(invocation);
                IsEnd = false;
            }
    
    
            /// <summary>
            /// 操作完成
            /// </summary>
            /// <param name="invocation"></param>
            public void OperationFinish(IInvocation invocation)
            {
                EndTime = DateTime.Now;
                TotalMilliseconds = (EndTime - StartTime).TotalMilliseconds;
                IsEnd = true;
            }
    
    
    
    
    
            //存放 所有的 详细信息
            public static List<MethodOperationInfo> operationInfos = new List<MethodOperationInfo>();
            
    
            /// <summary>
            /// 设置开始时间
            /// </summary>
            /// <param name="invocation"></param>
            public static void SetStartTime(IInvocation invocation)
            {
                MethodOperationInfo model = new MethodOperationInfo(invocation);
                operationInfos.Add(model);
            }
    
            /// <summary>
            /// 设置结束时间
            /// </summary>
            /// <param name="invocation"></param>
            public static void SetEndTime(IInvocation invocation)
            {
                MethodOperationInfo model = GetModel(invocation);
                model.OperationFinish(invocation);
            }
    
            /// <summary>
            /// 获取一个对象
            /// </summary>
            /// <param name="invocation"></param>
            /// <returns></returns>
            public static MethodOperationInfo GetModel(IInvocation invocation)
            {
                string name = GetName(invocation);
                return operationInfos.Where(c => (c.Name == name) && !c.IsEnd).FirstOrDefault();
            }
    
            /// <summary>
            /// 获取 这个方法 唯一的编号,针对方法而已
            /// </summary>
            /// <param name="invocation"></param>
            /// <returns></returns>
            public static string GetName(IInvocation invocation)
            {
                string NameSpaceName = invocation.TargetType.Namespace;
                string ClassName = invocation.TargetType.Name;
                string MethodName = invocation.Method.Name;//方法名
                string ParameterTypes = GetParameterTypes(invocation);
                string Parameters = GetParameter(invocation);//参数
    
                string strId = $"{NameSpaceName},{ClassName},{MethodName},{ParameterTypes}";
    
                //MD5加密
                byte[] result = Encoding.Default.GetBytes(strId);
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] output = md5.ComputeHash(result);
                return BitConverter.ToString(output).Replace("-", "");
            }
    
    
            /// <summary>
            /// 获取方法的参数类型
            /// 如:(System.String, System.Object, System.Int32)
            /// </summary>
            /// <param name="invocation"></param>
            /// <returns></returns>
            public static string GetParameterTypes(IInvocation invocation)
            {
                MethodInfo mInfo = invocation.Method;
                ParameterInfo[] pInfos = mInfo.GetParameters();
    
                string str = "";
                str += "(";
                for (int j = 0; j < pInfos.Length; j++)
                {
                    var p = pInfos[j];
                    string pTypeName = $"{p.ParameterType.ToString()}, ";
                    if (p.ParameterType.IsGenericType && (p.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                    {
                        pTypeName = $"{Nullable.GetUnderlyingType(p.ParameterType).Name}?, ";
                    }
                    str += pTypeName;
                }
                str = str.TrimEnd(' ').TrimEnd(',');
                str += ")";
    
                return str;
            }
    
            /// <summary>
            /// 获取方法的参数
            /// </summary>
            /// <param name="invocation"></param>
            /// <returns></returns>
            public static string GetParameter(IInvocation invocation)
            {
                string Parameters = "";//参数
                if ((invocation.Arguments != null) && (invocation.Arguments.Length > 0))
                {
                    Parameters = JsonConvert.SerializeObject(invocation.Arguments);
                }
                return Parameters;
            }
    
    
            /// <summary>
            /// 显示日志
            /// </summary>
            /// <param name="ShowDetailRecord">是否显示详情记录-比较占用时间</param>
            /// <param name="IsFilter">是否开启过滤</param>
            public static void Show(bool ShowDetailRecord = true, bool IsFilter = false)
            {
                StringBuilder sb = new StringBuilder();
                DateTime beforDT = DateTime.Now;
                List<string> list_Show_Method = new List<string>() { "GetSingle_Value1" };//可改为配置参数
    
    
    
                //每个方法-耗时            
                string str = "";
                double totalMilliseconds_AllMethod = 0;
    
    
                //去重
                var operationInfos_NotRepeat = operationInfos.GroupBy(c => c.Name).Select(c => c.First()).ToList();
    
                //分组统计
                operationInfos.GroupBy(c => c.Name).Select(c => new
                {
                    Name = c.Key,
                    ExecuteNumber = c.Count(),
                    TotalMilliseconds = c.Sum(a => a.TotalMilliseconds)
                }).ToList().ForEach(c =>
                {
                    var item = operationInfos_NotRepeat.Where(x => x.Name == c.Name).First();
                    totalMilliseconds_AllMethod += item.TotalMilliseconds;
    
                    str += $"命名空间:{item.NameSpaceName.ToString(40)}     ";
                    str += $"类名:{item.ClassName.ToString(30)}     ";
                    str += $"方法:{item.MethodName.ToString(80)}     ";
                    str += $"次数:{c.ExecuteNumber.ToString(10)}     ";
                    str += $"耗时:{c.TotalMilliseconds.ToString(10, false) }毫秒     ";
                    str += $"
    ";
                });
                sb.Append(str + "
    
    ");
    
                //方法-总耗时
                str = "";
                str += $"所有方法-耗时:{totalMilliseconds_AllMethod}毫秒    ";
                str += $"{totalMilliseconds_AllMethod / 1000}秒    ";
                str += $"{(totalMilliseconds_AllMethod / 1000 / 60).ToString("f2")}分钟    ";
                str += $"当前时间:{DateTime.Now}    ";
                sb.Insert(0, str + "
    
    ");
    
    
    
                #region 方法 每次耗时的 详情信息
    
                if (ShowDetailRecord)
                {
                    for (int i = 0; i < operationInfos.Count; i++)
                    {
                        Console.WriteLine($"处理数据-当前行:{operationInfos.Count - i}");
                        var item = operationInfos[i];
    
                        //数据过滤                   
                        if (IsFilter && !list_Show_Method.Contains(item.MethodName))
                        {
                            continue;
                        }
    
                        sb.Append($"命名空间:{item.NameSpaceName.ToString(40)}     ");
                        sb.Append($"类名:{item.ClassName.ToString(30)}     ");
                        sb.Append($"方法:{item.MethodName + item.ParameterTypes.ToString(80)}     ");
                        sb.Append($"耗时:{item.TotalMilliseconds.ToString(10, false) }毫秒     ");
                        sb.Append($"参数:{item.Parameters.ToString(50)}     ");
                        sb.Append($"
    ");
                    }
                }
                #endregion
    
                //计算日志-耗时
                sb.Insert(0, $"计算日志-耗时:{DateTime.Now.Subtract(beforDT).TotalSeconds.ToString("#0.00000")}秒 
    
    ");
    
    
                System.IO.File.WriteAllText($"LOG_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.txt", sb.ToString());
                Console.WriteLine("完成!");
            }
    
            /// <summary>
            /// 显示日志 包含详情数据
            /// </summary>
            public static void ShowContainsDetail()
            {
                Show(true);
            }
    
            /// <summary>
            /// 显示日志 不包含详情数据
            /// </summary>
            public static void ShowNotContainsDetail()
            {
                Show(false);
            }
        }
    
    
    
    
        
    
        /// <summary>
        /// 测试类1
        /// </summary>
        public class Class5_test1
        {
            public virtual void test1()
            {
                Console.WriteLine("主方法-test1-开始执行");
                Console.WriteLine();
    
                for (int i = 0; i < 4; i++)
                {
                    test4();
                }
                for (int i = 0; i < 3; i++)
                {
                    test3();
                }
                for (int i = 0; i < 2; i++)
                {
                    test2();
                }
    
                Console.WriteLine("主方法-test1-执行完成");
                Console.WriteLine();
            }
            public virtual void test2()
            {
                System.Threading.Thread.Sleep(200);
            }
            public virtual void test3()
            {
                System.Threading.Thread.Sleep(300);
            }
            public virtual void test4()
            {
                System.Threading.Thread.Sleep(400);
            }
        }
    
    
    
    
    
    
    
    
    }
    View Code

    但是当要代理的那个的类,如果没有无参构造函数,这种方法就还是用不了,准备解决这个问题,解决了到时候再贴上解决方案。

    本来是准备用到生产环境测试一下自己的代码的,结果,我去,有参构造函数,接口,多态,麻蛋都有啊,改好了,再继续贴代码

  • 相关阅读:
    iOS开发UI篇—字典转模型
    iOS开发UI篇—懒加载
    iOS开发UI篇—九宫格坐标计算
    iOS开发UI篇—简单的浏览器查看程序
    iOS开发UI篇—transframe属性(形变)
    iOS开发UI篇—Button基础
    OS开发UI基础—手写控件,frame,center和bounds属性
    Foundation框架—集合
    Foundation框架—字符串
    uvalive 4255 Guess(拓扑排序)
  • 原文地址:https://www.cnblogs.com/guxingy/p/11063298.html
Copyright © 2020-2023  润新知