问题描述
我正在考虑使用类似 StackFrame stackFrame = new StackFrame(1)
的东西来记录执行方法,但我不知道它的性能影响.堆栈跟踪是在每个方法调用中构建的,因此性能不应该成为问题,还是仅在需要时构建?您是否建议在性能非常重要的应用程序中使用它?如果是这样,这是否意味着我应该在发布时禁用它?
一些背景
我们有一个类似的功能,在 99% 的情况下都被禁用;我们使用的方法是:
public void DoSomething(){TraceCall(MethodBase.GetCurrentMethod().Name);//做一点事}public void TraceCall(string methodName){如果(!loggingEnabled){返回;}//日志...}TraceCall(MethodBase.GetCurrentMethod().Name)
这很简单,但无论是否启用跟踪,我们都会因使用反射查找方法名称而导致性能下降.
我们的选择是要么在每个方法中都需要更多的代码(并冒着简单错误或拒绝的风险),要么切换到使用 StackFrame
来确定调用方法 only 在记录时已启用.
选项 A:
public void DoSomething(){如果(日志记录已启用){TraceCall(MethodBase.GetCurrentMethod().Name);}//做一点事}public void TraceCall(string methodName){如果(!loggingEnabled){返回;}//日志...}
选项 B:
public void DoSomething(){跟踪调用();//做一点事}公共无效 TraceCall(){如果(!loggingEnabled){返回;}StackFrame stackFrame = new StackFrame(1);//日志...}
我们选择了选项 B.它比选项 A 提供了显着的性能改进禁用日志记录时,99% 的时间并且实施起来非常简单.>
这是迈克尔代码的一个改动,以显示这种方法的成本/收益
使用系统;使用 System.Diagnostics;使用 System.Reflection;命名空间控制台应用程序{课程计划{静态布尔跟踪调用;静态无效主(字符串 [] args){秒表开关;//暖身for (int i = 0; i
结果:
跟踪禁用,传递方法名称:294ms启用跟踪,传递方法名称:298ms跟踪禁用,查找方法名称:0ms启用跟踪,查找方法名称:1230ms
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?
edit: Some background
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.
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.
Option A:
public void DoSomething()
{
if (loggingEnabled)
{
TraceCall(MethodBase.GetCurrentMethod().Name);
}
// Do Something
}
public void TraceCall(string methodName)
{
if (!loggingEnabled) { return; }
// Log...
}
Option B:
public void DoSomething()
{
TraceCall();
// Do Something
}
public void TraceCall()
{
if (!loggingEnabled) { return; }
StackFrame stackFrame = new StackFrame(1);
// Log...
}
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.
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
}
}
}
The Results:
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
这篇关于StackFrame 的性能如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!