8

与测试小于零的整数甚至 bool 为假相比,测试C# 中的引用类型变量是否为空指针(如if (x == null)...)的性能如何?

关于此类空指针测试是否还有其他问题,例如是否产生了垃圾

我对游戏的每一帧都进行了数百次这样的测试,我想知道这些测试是否会导致问题或者可以更有效地实施?

4

6 回答 6

12

空值测试可能等同于简单的“等于 0”测试。它们非常非常便宜 - 除非您拥有数百万的帧速率,否则每帧只有数百个应该完全微不足道:)

您应该分析您的应用程序以找出实际花费的时间 - 这比猜测更有效率。理想情况下,您还应该尝试编写一些基准测试,这样您不仅可以衡量当前的性能,还可以注意到它是否由于任何特定的变化而变得明显更糟。

于 2013-01-11T12:55:56.833 回答
4

测试 null 的值不是需要类型检查或类似的复杂操作,并且不涉及内存分配。

反汇编语句if (x == null)给出:

00000030  cmp         qword ptr [rsp+20h],0
00000036  jne         000000000000004A

即测试被实现为指针值的简单整数比较。

于 2013-01-11T13:01:47.907 回答
2

但是,像您这样进行密集检查可能会导致性能下降,这只能通过您自己的标准针对您的特定应用程序来衡量。

根据测试的重点,可能还有其他方法可以让您更聪明地了解检查的内容和时间。但是,如果不了解更多有关您的应用程序的信息,就很难想出一个答案。

于 2013-01-11T12:56:38.740 回答
2

可能是主观的 - 但空检查等同于等于零检查,并且同样快速。所以我认为你不应该担心这个。

同样 - 除非你有性能问题,否则为什么还要玩它。

同样,如果您确实有性能问题,那么您很可能能够从复杂的代码分支中获得性能,而不是消除一些空检查。

也就是说,对于条件代码,潜在的性能改进(但它确实需要进行基准测试)可能是使用代表作为一个或多个条件更改的结果设置的不同逻辑分支 - 但我会如果这样的解决方案在一般情况下实际上提高了性能,会感到惊讶——尤其是对于您的“为空”场景。所以,我的意思是这样的:

if([condition])
{
  Foo();
}
else
{
  Bar();
}

如果,说,[condition]涉及一个局部变量_obj(在你的情况下_obj == null) - 你可以用这样的东西替换(但要非常小心线程问题):

private Action _logic;
private object _obj;
public Object Obj {
  get { return Obj; }
  set {
    _obj=value;
    if([condition])
      _logic = () => Foo();
    else
      _logic = () => Bar();
  }
}

现在,在您之前检查[condition]过进行分支的任何代码中,您现在只需执行以下操作:

_logic();

这种事情在[condition]复杂的情况下获得了最大的改进,而且至关重要的是,已通过分析证明占用了大量的处理器时间。使用委托也会在条件分支上产生轻微的开销,但如果该开销小于执行的[condition]那么它可能会产生影响,特别是如果这些检查被非常频繁地执行。

这也有其他变体,最常见的是从一个值派生的函数查找表,而不是基于相等性检查选择代码分支(这是可以实现大型 switch/case 语句的方式 - 委托添加到Dictionary由枚举键入的/value 被检查 - 这避免了对值的多次检查)。

但是,最终,如果没有尽职的分析(当然是之前和之后),执行这样的优化基本上是没有意义的。

于 2013-01-11T13:04:56.690 回答
1

没有问题(性能或其他)if (x == null)

于 2013-01-11T12:55:51.880 回答
1

这绝对没有问题-您提到的所有测试通常都需要一个时钟周期。如果条件分支对性能有影响,则通常是由不可预测的或至少难以预测的分支行为破坏分支预测器并要求中止推测执行的分支引起的。

于 2013-01-11T12:58:25.207 回答