【问题标题】:Compare 2 method's performance比较 2 方法的性能
【发布时间】:2013-12-19 08:44:21
【问题描述】:

我有以下几点:

public class Logger
{
    public static void LogStartMethod(MethodBase method)
    {
        Console.WriteLine("{0} Method '{1}' started", DateTime.Now, method.Name);
    }

    public static void LogStartMethod1()
    {
        StackTrace stackTrace = new StackTrace();
        MethodBase method = stackTrace.GetFrame(0).GetMethod();
        LogStartMethod(method);
    }

    public static void LogStartMethod2()
    {
        MethodBase method = MethodBase.GetCurrentMethod();
        LogStartMethod(method);
    }
}

我想确定 LogStartMethod1 或 LogStartMethod2 之间性能最高的方法...

让我们抽象一下具体方法的作用,但是否有工具(在线或 Visual Studio 插件)能够比较两种方法的性能?

我现在有很多商业性能分析器......我们应该付费或使用 Visual Studio Ultimate 来为整个解决方案提供性能工具......

我只想比较2种方法,都是……

【问题讨论】:

  • Performance 完全是主观的。速度?内存使用情况?内存泄漏? CPU 使用率?
  • 速度......如果可能的内存使用,为什么不,但速度很重要。
  • 性能分析也包含在 Visual Studio Premium 中。
  • 你想在这里实现什么?你只是想输出调用方法吗?
  • @Serge 昨晚有个想法,在运行时分析堆栈时小心。您在发布模式下获得的堆栈跟踪可能会更短。这是因为编译器倾向于内联较小的方法(如属性访问器)。不要依赖输出!

标签: .net visual-studio-2010 performance-testing


【解决方案1】:

VS 12 Ultimate:查看菜单项ANALYZE & Start Performance Analysis --- 它提供了有趣的反馈,不仅与 2 种方法有关 --- 本周已经尝试过,结果对于当前状态和未来方向都非常有成果一些编码问题。

【讨论】:

  • 好吧,但通常一个程序包含两个以上的方法 ;-)
  • 我必须在两种方法之间做出选择。所以我问的不是如何飞到月球,而是如何制造纸飞机。
【解决方案2】:

StopWatch 类可以测量速度。
测试前拨打StopWatch.Start,测试后拨打StopWatch.Stop

请记住在发布模式下运行速度测试,而不是调试模式。

【讨论】:

  • 所以,为了测试我的2个方法,我应该新建一个项目,把我的类放在那里,使用StopWatch前后,使用发布模式,输出结果......太经典了我想也许有人在网上发布了类似的东西......:-/
  • @Serge: 做起来好难啊,你自己能用much写的这种代码,为什么还要花时间去搜索、下载、修改呢?更少的时间?
【解决方案3】:

我建议在两种解决方案中简单地使用Performance Counters,一种使用方法LogStartMethod1,第二种使用LogStartMethod2。连续调用这个方法几分钟,观察像% Processor Time.NET CLR Memory这样的计数器来运行进程,当然测量方法执行的总数。然后您会看到处理时间的差异以及 CPU 和内存消耗的差异。

【讨论】:

    【解决方案4】:

    我现在可以告诉你,任何组装堆栈跟踪的代码都会比不组装堆栈跟踪的类似(tm) 代码慢。

    获取调用方法名称的最快方法是使用System.Runtime.CompilerServices.CallerMemberName 属性。编译代码时,编译将方法名称作为字符串文字插入。它非常快,但需要 C# .5

    这是我经过试验和测试的 perf 代码,其中包含用于演示问题的示例方法:

    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, Action> tasks = new Dictionary<string, Action>();
            List<string> results = new List<string>();
    
            tasks.Add("Task 1", Task1);
            tasks.Add("Task 2", Task2);
            tasks.Add("Task 3", Task3);
    
            string input = "This is a sample string";
            int count = 9999;
    
            Console.Write("Warming up...");
            foreach (var item in tasks.Values)
            {
                item();
            }
            Console.WriteLine("Done.");
    
            Console.WriteLine();
            Console.WriteLine();
    
            foreach (var item in tasks)
            {
                var time = RunPerf(item.Key, count, item.Value);
                results.Add(string.Format("{0}\t\t{1}", item.Key, time));
            }
    
            Console.WriteLine();
            Console.WriteLine("RESULTS");
            foreach (var item in results)
            {
                Console.WriteLine(item);
            }
    
            Console.ReadLine();
        }
    
        public static void Task1()
        {
            StackTrace stackTrace = new StackTrace();
            MethodBase method = stackTrace.GetFrame(0).GetMethod();
            LogStartMethod(method);
        }
    
        public static void Task2()
        {
            MethodBase method = MethodBase.GetCurrentMethod();
            LogStartMethod(method);
        }
    
        public static void Task3()
        {
            LogStartMethod();
        }
    
        public static void LogStartMethod(MethodBase method)
        {
            Console.WriteLine("{0} Method '{1}' started", DateTime.Now, method.Name);
        }
        public static void LogStartMethod([System.Runtime.CompilerServices.CallerMemberName]string methodName = null)
        {
            Console.WriteLine("{0} Method '{1}' started", DateTime.Now, methodName);
        }
    
        static TimeSpan RunPerf(string name, int count, Action action)
        {
            var sw = new System.Diagnostics.Stopwatch();
            Console.WriteLine(string.Format("Starting perf for {0}. {1} times", name, count));
    
            sw.Start();
            for (int i = 0; i < count; i++)
            {
                action();
            }
            sw.Stop();
            Console.WriteLine(string.Format("{0} completed in {1}", name, sw.Elapsed));
    
            return sw.Elapsed;
        }
    }
    

    注意。请务必在发行版中运行此代码。它需要 C#5。我建议使用 .net 4.5 项目

    RESULTS
    Task 1          00:00:00.7226149
    Task 2          00:00:00.5001454
    Task 3          00:00:00.4690296
    

    【讨论】:

    • 事实上,我只是想减少代码...如果我只是通过“LogStart();”开始一个方法并且在“stackTrace.GetFrame(1)”内部标识调用者较少写“method = GetCurrentMethod()”然后是“LogStart(method)”......但我看到我为了简单而失去了一些性能......
    • @Serge 进一步更新第三个任务。查看代码,这很神奇。
    • 这个Task3非常有趣...!干得好......不幸的是我的项目是在 .NET 3.5 中,但我会将此属性用于其他项目......
    猜你喜欢
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    • 2021-09-03
    • 2013-10-09
    • 1970-01-01
    • 2010-09-15
    相关资源
    最近更新 更多