请考虑以下代码:
if (IsDebuggingEnabled) {
instance.Log(GetDetailedDebugInfo());
}
GetDetailedDebugInfo()
可能是一种昂贵的方法,所以我们只想在调试模式下运行时调用它。
现在,更清洁的替代方案是编写类似这样的代码:
instance.Log(() => GetDetailedDebugInfo());
其中.Log()的定义如下:
public void Log(Func<string> getMessage)
{
if (IsDebuggingEnabled)
{
LogInternal(getMessage.Invoke());
}
}
我关注的是性能,初步测试没有显示第二种情况特别昂贵,但如果负载增加,我不想遇到任何意外。
哦,请不要建议条件编译,因为它不适用于这种情况。
(P.S。:我直接在StackOverflow中编写代码问一个问题textarea所以不要怪我,如果有微小的错误而且它没有编译,你明白了这一点:)
答案 0 :(得分:5)
不,它不应该有不好的表现。毕竟,只有在性能不是最重要的调试模式下才会调用它。实际上,您可以删除lambda并只传递方法名称以消除不必要的中间匿名方法的开销。
请注意,如果要在Debug版本中执行此操作,可以在日志方法中添加[Conditional("DEBUG")]
属性。
答案 1 :(得分:3)
性能有所不同。它的重要性取决于你的其余代码,所以我建议在开始优化之前进行性能分析。
对你的第一个例子说:
if (IsDebuggingEnabled)
{
instance.Log(GetDetailedDebugInfo());
}
如果IsDebuggingEnabled是静态只读,那么检查将被丢弃,因为它知道它永远不会改变。这意味着如果IsDebuggingEnabled为false,上面的示例将没有性能影响,因为在JIT完成后代码将消失。
instance.Log(() => GetDetailedDebugInfo());
public void Log(Func<string> getMessage)
{
if (IsDebuggingEnabled)
{
LogInternal(getMessage.Invoke());
}
}
每次调用该方法时都会调用该方法。哪个会慢一些。
但在花费时间进行微观优化之前,您应该对应用程序进行概要分析或运行一些性能测试,以确保这实际上是您应用程序的瓶颈。
答案 2 :(得分:3)
我希望在这种情况下提供一些关于性能的文档,但似乎我得到的是关于如何改进我的代码的建议......似乎没有人读过我的P.S. - 没有分数。
所以我写了一个简单的测试用例:
public static bool IsDebuggingEnabled { get; set; }
static void Main(string[] args)
{
for (int j = 0; j <= 10; j++)
{
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i <= 15000; i++)
{
Log(GetDebugMessage);
if (i % 1000 == 0) IsDebuggingEnabled = !IsDebuggingEnabled;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
Console.ReadLine();
for (int j = 0; j <= 10; j++)
{
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i <= 15000; i++)
{
if (IsDebuggingEnabled) GetDebugMessage();
if (i % 1000 == 0) IsDebuggingEnabled = !IsDebuggingEnabled;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
Console.ReadLine();
}
public static string GetDebugMessage()
{
StringBuilder sb = new StringBuilder(100);
Random rnd = new Random();
for (int i = 0; i < 100; i++)
{
sb.Append(rnd.Next(100, 150));
}
return sb.ToString();
}
public static void Log(Func<string> getMessage)
{
if (IsDebuggingEnabled)
{
getMessage();
}
}
两个版本之间的时间似乎完全相同。 我在第一种情况下得到145 ms,在第二种情况下得到145 ms
看起来我回答了自己的问题。
答案 3 :(得分:1)
你也可以这样做:
// no need for a lambda
instance.Log(GetDetailedDebugInfo)
// Using these instance methods on the logger
public void Log(Func<string> detailsProvider)
{
if (!DebuggingEnabled)
return;
this.LogImpl(detailsProvider());
}
public void Log(string message)
{
if (!DebuggingEnabled)
return;
this.LogImpl(message);
}
protected virtual void LogImpl(string message)
{
....
}
答案 4 :(得分:0)
直接调用getMessage委托,而不是在其上调用Invoke。
if(IsDebuggingEnabled)
{
LogInternal(getMessage());
}
您还应该在getMessage上添加空检查。
答案 5 :(得分:0)
标准答案:
答案 6 :(得分:-3)
我相信代理人创建了一个新线程,所以你可能会对它提高性能。 为什么不设置像Dav建议的测试运行,并密切关注应用程序生成的线程数,您可以使用Process Explorer。
坚持下去!我已经纠正了!代表只在您使用'BeginInvoke'时使用线程...所以我的上述注释不适用于您使用它们的方式。