假设我们有这样一个类:
public class Task
{
public Action PostAction=()=>{}
public void Do()
{
//Do Some Stuffs
PostAction();
}
}
正如您所见,PostAction就在那里,所以我们可以注入一个帖子。
现在假设我们有一个任务列表,其中一些人有一个帖子,其中大部分都没有,我们这样称呼他们:
foreach(var task in tasks)
task.Do();
空帖子操作是否对上述代码的执行有任何性能影响?
答案 0 :(得分:5)
这经常出现,因为你的代码也是在你举起一个事件时必须做空测试的黑客。抖动优化器无法做任何事情来优化do-nothing调用,它不能超出委托调用。此代码的快速版本避免了委托调用:
public class Task {
public Action PostAction;
public void Do() {
if (PostAction != null) PostAction();
}
}
使用System.Diagnostics.Stopwatch分析差异非常棘手,委托调用速度非常快。我确保通过给它[MethodImpl(MethodImplOptions.Noinlining)]属性来内联Do()调用。使用移动Haswell芯片的非常快的笔记本电脑的平均测量值:
请注意" Empty Do()"测量包括执行测试的开销,for(;;)循环以及进行方法调用。这是所有测量中不变的开销。
你可以告诉费用,委托调用比null测试慢(3.6 - 0.4)/ 0.4~ = 800%。如果你假设恒定开销具有代表性(它不是),你可以得到更友好的数字:( 7.5 - 4.3)/ 4.3~ = 75%慢。您的foreach循环将有更多的开销,从而降低了穿孔损失百分比。使用带有foreach的Enumerable.Range进行迭代测试(17.0 - 13.9)/ 13.9~ = 22%慢。
当然,这些数字相当可观。但是,绝对数字非常低。如果你不经常给代表打电话,或者有很多//Do Some Stuffs
(从而增加了不断的开销),那么很难注意到性能损失。
测试null,如演示如何引发事件的任何示例代码所示,是推荐的方法。如果你非常期望代表将被替换(即事件将被订阅),你只有充分的理由使用lambda。在这种情况下,您优化了空检查,每次调用节省大约一个CPU周期。