如何高性能是的StackFrame?是的、高性能、StackFrame

2023-09-02 10:35:00 作者:老师,我晕课

我正在考虑使用类似的StackFrame的StackFrame =新的StackFrame(1)登录一个执行的方法,但我不知道它的性能影响。是堆栈跟踪的东西,是每个方法调用反正建所以性能不应该是一个问题或者是它的东西是只能建在被问到呢?你在一个应用程序,性能是非常重要的建议反对呢?如果是的话,这是否意味着我应该禁用它的发布?

I am considering using something like StackFrame stackFrame = new StackFrame(1) to log the executing method, but I don't know about its performance implications. Is the stack trace something that is build anyway with each method call so performance should not be a concern or is it something that is only build when asked for it? Do you recommend against it in an application where performance is very important? If so, does that mean I should disable it for the release?

推荐答案

编辑:一些背景

我们有一个类似的功能,它处于关闭状态99%的时间;我们使用类似的方法:

We have a similar feature which is disabled 99% of the time; we were using an approach like:

public void DoSomething()
{
    TraceCall(MethodBase.GetCurrentMethod().Name);
    // Do Something
}

public void TraceCall(string methodName)
{
    if (!loggingEnabled) { return; }
    // Log...
}

TraceCall(MethodBase.GetCurrentMethod().Name)

这是简单的,但无论与否跟踪启用我们承担使用反射来查找方法名的性能损失。

It was simple, but regardless of whether or not tracing was enabled we were incurring the performance hit of using Reflection to lookup the method name.

我们的选择是要么需要更多的code在每一个方法(和风险简单的错误或拒绝),或者切换到使用的StackFrame 确定调用方法仅的时候启用日志记录。

Our options were to either require more code in every method (and risk simple mistakes or refusal) or to switch to using StackFrame to determine the calling method only when logging was enabled.

选项A:

public void DoSomething()
{
    if (loggingEnabled)
    {
        TraceCall(MethodBase.GetCurrentMethod().Name);
    }
    // Do Something
}

public void TraceCall(string methodName)
{
    if (!loggingEnabled) { return; }
    // Log...
}

选项B:

public void DoSomething()
{
    TraceCall();
    // Do Something
}

public void TraceCall()
{
    if (!loggingEnabled) { return; }
    StackFrame stackFrame = new StackFrame(1);
    // Log...
}

我们选择了选项B.它在选项提供显著的性能提升A 登录时禁用,99%的时间的并很容易实现的。

We opted for Option B. It offers significant performance improvements over Option A when logging is disabled, 99% of the time and is very simple to implement.

下面是迈克尔的code的改变,以显示这种方法的成本/效益

Here's an alteration of Michael's code, to display the cost / benefit of this approach

using System;
using System.Diagnostics;
using System.Reflection;

namespace ConsoleApplication
{
	class Program
	{
		static bool traceCalls;

		static void Main(string[] args)
		{
			Stopwatch sw;

			// warm up
			for (int i = 0; i < 100000; i++)
			{
				TraceCall();
			}

			// call 100K times, tracing *disabled*, passing method name
			sw = Stopwatch.StartNew();
			traceCalls = false;
			for (int i = 0; i < 100000; i++)
			{
				TraceCall(MethodBase.GetCurrentMethod());
			}
			sw.Stop();
			Console.WriteLine("Tracing Disabled, passing Method Name: {0}ms"
							 , sw.ElapsedMilliseconds);

			// call 100K times, tracing *enabled*, passing method name
			sw = Stopwatch.StartNew();
			traceCalls = true;
			for (int i = 0; i < 100000; i++)
			{
				TraceCall(MethodBase.GetCurrentMethod());
			}
			sw.Stop();
			Console.WriteLine("Tracing Enabled, passing Method Name: {0}ms"
							 , sw.ElapsedMilliseconds);

			// call 100K times, tracing *disabled*, determining method name
			sw = Stopwatch.StartNew();
			traceCalls = false;
			for (int i = 0; i < 100000; i++)
			{
				TraceCall();
			}
			Console.WriteLine("Tracing Disabled, looking up Method Name: {0}ms"
					   , sw.ElapsedMilliseconds);

			// call 100K times, tracing *enabled*, determining method name
			sw = Stopwatch.StartNew();
			traceCalls = true;
			for (int i = 0; i < 100000; i++)
			{
				TraceCall();
			}
			Console.WriteLine("Tracing Enabled, looking up Method Name: {0}ms"
					   , sw.ElapsedMilliseconds);

			Console.ReadKey();
		}

		private static void TraceCall()
		{
			if (traceCalls)
			{
				StackFrame stackFrame = new StackFrame(1);
				TraceCall(stackFrame.GetMethod().Name);
			}
		}

		private static void TraceCall(MethodBase method)
		{
			if (traceCalls)
			{
				TraceCall(method.Name);
			}
		}

		private static void TraceCall(string methodName)
		{
			// Write to log
		}
	}
}

结果:

Tracing Disabled, passing Method Name: 294ms
Tracing Enabled,  passing Method Name: 298ms
Tracing Disabled, looking up Method Name: 0ms
Tracing Enabled,  looking up Method Name: 1230ms
 
精彩推荐
图片推荐