过度使用委托对性能来说是一个坏主意吗?
考虑以下代码:
if (IsDebuggingEnabled) {
instance.Log(GetDetailedDebugInfo());
}
GetDetailedDebugInfo()
可能是一个昂贵的方法,因此我们只想在调试模式下运行时调用它。
现在,更干净的替代方案是编写如下代码:
instance.Log(() => GetDetailedDebugInfo());
其中 .Log() 定义如下:
public void Log(Func<string> getMessage)
{
if (IsDebuggingEnabled)
{
LogInternal(getMessage.Invoke());
}
}
我关心的是性能,初步测试并没有显示第二种情况特别昂贵,但我不想如果负载增加,会遇到任何意外。
哦,请不要建议条件编译,因为它不适用于这种情况。
(PS:我直接在 StackOverflow 提问文本区域中编写了代码,所以如果有细微的错误并且无法编译,请不要责怪我,你明白了:)
Consider the following code:
if (IsDebuggingEnabled) {
instance.Log(GetDetailedDebugInfo());
}
GetDetailedDebugInfo()
may be an expensive method, so we only want to call it if we're running in debug mode.
Now, the cleaner alternative is to code something like this:
instance.Log(() => GetDetailedDebugInfo());
Where .Log() is defined such as:
public void Log(Func<string> getMessage)
{
if (IsDebuggingEnabled)
{
LogInternal(getMessage.Invoke());
}
}
My concern is with performance, preliminary testing doesn't show the second case to be particularly more expensive, but I don't want to run into any surprises if load increases.
Oh, and please don't suggest conditional compilation because it doesn't apply to this case.
(P.S.: I wrote the code directly in the StackOverflow Ask a Question textarea so don't blame me if there are subtle bugs and it doesn't compile, you get the point :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
不,应该不会有什么不好的表现。 毕竟,您只会在性能不是最重要的调试模式下调用它。 实际上,您可以删除 lambda 并仅传递方法名称,以消除不必要的中间匿名方法的开销。
请注意,如果您想在调试版本中执行此操作,您可以添加
[Conditional("DEBUG")]
日志方法的属性。No, it shouldn't have a bad performance. After all, you'll be calling it only in debug mode where performance is not at the forefront. Actually, you could remove the lambda and just pass the method name to remove the overhead of an unnecessary intermediate anonymous method.
Note that if you want to do this in Debug builds, you can add a
[Conditional("DEBUG")]
attribute to the log method.性能上有差异。 它的重要性取决于代码的其余部分,因此我建议在开始优化之前进行分析。
话虽如此,对于您的第一个示例:
如果 IsDebuggingEnabled 是静态只读,那么检查将被丢弃,因为它知道它永远不会改变。 这意味着如果 IsDebuggingEnabled 为 false,上述示例对性能的影响为零,因为 JIT 完成后代码将消失。
每次调用instance.Log时都会调用该方法。 哪个会更慢。
但在花时间进行这种微观优化之前,您应该分析您的应用程序或运行一些性能测试,以确保这实际上是您应用程序中的瓶颈。
There is a difference in performance. How significant it is will depend on the rest of your code so I would recommend profiling before embarking on optimisations.
Having said that for your first example:
If IsDebuggingEnabled is static readonly then the check will be jitted away as it knows it can never change. This means that the above sample will have zero performance impact if IsDebuggingEnabled is false, because after the JIT is done the code will be gone.
The method will be called every time instance.Log is called. Which will be slower.
But before expending time with this micro optimization you should profile your application or run some performance tests to make sure this is actually a bottle neck in your application.
我希望获得一些有关这种情况下性能的文档,但似乎我得到的只是有关如何改进我的代码的建议......似乎没有人读过我的 PS - 没有给你分。
所以我写了一个简单的测试用例:
两个版本之间的时序似乎完全相同。
我在第一种情况下得到 145 毫秒,在第二种情况下得到 145 毫秒
看起来我回答了我自己的问题。
I was hoping for some documentation regarding performance in such cases, but it seems that all I got were suggestions on how to improve my code... No one seems to have read my P.S. - no points for you.
So I wrote a simple test case:
Timings seem to be exactly the same between the two versions.
I get 145 ms in the first case, and 145 ms in the second case
Looks like I answered my own question.
您还可以这样做:
You can also do this:
我相信委托会创建一个新线程,因此您关于它提高性能的说法可能是正确的。
为什么不像 Dav 建议的那样设置测试运行,并密切关注应用程序生成的线程数量,您可以使用 Process Explorer 来实现这一点。
不挂断! 我已经纠正了! 当您使用“BeginInvoke”时,委托仅使用线程...因此我的上述评论不适用于您使用它们的方式。
I believe delegates create a new thread, so you may be right about it increasing performance.
Why not set up a test run like Dav suggested, and keep a close eye on the number of threads spawned by your app, you can use Process Explorer for that.
Hang on! I've been corrected! Delegates only use threads when you use 'BeginInvoke'... so my above comments don't apply to the way you're using them.
直接调用 getMessage 委托,而不是对其调用 Invoke。
您还应该对 getMessage 添加 null 检查。
Call getMessage delegate directly instead of calling Invoke on it.
You should also add null check on getMessage.
标准答案:
Standard answers: