空指针测试性能

Posted

技术标签:

【中文标题】空指针测试性能【英文标题】:Null pointer test performance 【发布时间】:2012-12-26 01:27:22 【问题描述】:

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

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

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

【问题讨论】:

你应该试试,写一些性能测试就行了 “过早的优化是万恶之源。”....如果我再听到这句话...... @venneto OP 表示他正在用 C# 制作游戏。因此,不要在每一帧都创建垃圾,因为它会导致 GC 运行,这一点至关重要。因此,您可以认为这不是过早的优化,因为这可能会直接改变设计决策。 @pad_ares: 1. 成功。 2. 让它运行。 3. 让它跑得快。按这个顺序:) 我认为这些说以后要优化的人中的很多人从来没有用托管语言设计过游戏。 【参考方案1】:

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

【讨论】:

【参考方案2】:

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

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

【讨论】:

关于跟踪性能的优点,而不仅仅是不时测量它 如果这个分支总是 false 或 true,动态分支预测会大大降低其性能影响。所以我毫不犹豫地进行这些安全检查。 @ares_games【参考方案3】:

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

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

【讨论】:

我在这里没有看到密集检查的证据。 @JonSkeet "我对游戏的每一帧都进行了数百次这样的测试" - 我会说根据有多少分类为 密集型每秒帧数。 我不同意。你有任何idea大多数游戏每帧可能做多少工作? 100 个非常便宜的测试不太可能根本,除非您期望帧速率达到数十万。假设它是200fps。那是每秒 20,000 次无效检查。即使在功率非常低的计算机上,这也不会很重要。 @JonSkeet 每秒 20,000 次无效检查(针对应用程序的一小部分)是密集的 IMO - 你的显然不同。但是,我不编写游戏应用程序,这就是为什么我说“只能根据您自己的标准针对您的特定应用程序进行衡量”。我的意思是 - 可能有更聪明的做事方式。【参考方案4】:

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

【讨论】:

【参考方案5】:

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

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

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

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

【讨论】:

【参考方案6】:

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

同样 - 除非您遇到性能问题,否则何必费心使用它。

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

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

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 语句的方式 - 委托添加到 @ 987654330@ 由正在检查的枚举/值键入 - 这避免了对值的多次检查。

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

【讨论】:

以上是关于空指针测试性能的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 中测试时出现空指针异常

java的equals提示空指针异常

测试数据时如何避免空指针异常

C语言 野指针和空指针

C语言 野指针和空指针

在 Spring Boot 2 中测试组件时的空指针