実行中のメソッドをログに記録するために、このようなものを使用することを検討していますStackFrame stackFrame = new StackFrame(1)
が、パフォーマンスへの影響についてはわかりません。スタック トレースは、各メソッド呼び出しでいずれにせよ作成されるものなので、パフォーマンスは問題にならないのでしょうか。それとも、要求された場合にのみ作成されるものなのでしょうか。パフォーマンスが非常に重要なアプリケーションでは、これを推奨しませんか。そうであれば、リリース時に無効にする必要があるという意味ですか。
ベストアンサー1
99% の確率で無効になっている同様の機能があり、次のようなアプローチを使用していました。
public void DoSomething()
{
TraceCall(MethodBase.GetCurrentMethod().Name);
// Do Something
}
public void TraceCall(string methodName)
{
if (!loggingEnabled) { return; }
// Log...
}
TraceCall(MethodBase.GetCurrentMethod().Name)
シンプルでしたが、トレースが有効になっているかどうかに関係なく、リフレクションを使用してメソッド名を検索するとパフォーマンスが低下しました。
StackFrame
我々の選択肢は、すべてのメソッドにさらにコードを要求するか(単純な間違いや拒否のリスクがある)、呼び出しメソッドを決定するためにを使用するかのいずれかでした。のみログ記録が有効になったとき。
オプション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%の確率で実装も非常に簡単です。
これは、このアプローチのコストと利点を示すためにマイケルのコードを変更したものです。
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