public class Test : MonoBehaviour
{
public GameObject prefab;
private IEnumerator Start ( )
{
var go = Instantiate(prefab);
Destroy(go);
Debug.Log ( $"go is null: {go is null}. go == null: {go == null}." ); // False False.
yield return null; // skip to next frame
Debug.Log ( $"go is null: {go is null}. go == null {go == null}." ); // False True.
yield return null; // skip to next frame
var sw = new Stopwatch();
sw.Start ( );
for ( var i = 0; i < 10_000_000; ++i )
_ = go is null;
sw.Stop ( );
Debug.Log ( $"go is null: {sw.ElapsedMilliseconds} ms" ); // Test machine : ~10 ms
sw.Reset ( );
sw.Start ( );
for ( var i = 0; i < 10_000_000; ++i )
_ = go == null;
sw.Stop ( );
Debug.Log ( $"go == null: {sw.ElapsedMilliseconds} ms" ); // Test machine : ~4000 ms
yield return null; // skip to next frame
Debug.Log ( $"go is null: {go is null}. go == null {go == null}." ); // STILL False True.
#if UNITY_EDITOR
EditorApplication.ExitPlaymode ( );
#endif
}
}
2条答案
按热度按时间5gfr0r5j1#
一般来说,像这样的问题可以归入“意见”类别,但在这种情况下,我们可以通过运行一个小测试来量化答案。
事实上,这里发生了一些事情,还有一个更深层次的问题。
我将从测试代码开始:
因此,首先要注意的是,在示例化并立即销毁一个对象之后,在该特定帧中,该对象在托管或非托管“内存”中均未被“销毁”,如“False False”所示。
然而,当我们跳到下一帧时,你会注意到unmanaged(Unity后端处理)已经将对象标记为null。尽管有一个问题,托管代码仍然看到
go
引用了一个对象,它有点不再是一个有效的后端对象。这就是为什么下一个调试行将为null检查指示“False True”。我提出这个问题的原因是因为一些开发人员错误地认为短路和绕过重载的'=='操作符是好的。它在大多数情况下都有效,对吗?很明显,它没有,正如这里所演示的。
那么,现在来看看使用“==”的时机。使用
object == null
和object is null
之间有着巨大的差异。正如您所看到的,使用“==”要慢400倍。这是因为Unity重载了“==”操作符,不仅要检查引用是否为空,还要检查底层后端对象是否也为空。这是一个代价高昂的过程(相对而言),这就是为什么人们说要避免它。但是,仅仅因为其他东西更快,并不能使它更好,在这种情况下,使用更快的检查可能会导致错误。解决方案是自己跟踪托管引用。要做到这一点,您需要执行以下操作:
如果每次销毁Unity对象时都将引用设置为null,则可以使用
object is null
安全地检查引用的null状态,object is null
比object == null
快得多。*说了这么多
请注意,为了在
StopWatch
中获得任何有意义的毫秒值,我不得不循环检查1000万次!这就引出了我的最后一点......除了担心“==”是否昂贵之外,还有很多其他地方可以提高游戏的性能。使用它,并专注于代码的其余部分。k5hmc34c2#
对支票昂贵的回答如下:
“转换到本机代码的成本可能很高,因为Unity将执行查找和验证,以将脚本引用转换为本机引用。比较Unity对象与null的成本虽然很小,但比与普通C#类进行比较的成本高得多,因此应避免在性能关键上下文和循环中使用。”
**尽管如此,我还是听到许多开发人员同事说,检查根本不是很密集,除非是垃圾邮件或大量使用。**只有当您的项目性能开始下降时,您才应该真正担心它。
但是,该代码的一个不太密集的版本如下所示:
//使用gameObject执行操作}
以下是两个答案和进一步解释的链接:
https://github.com/JetBrains/resharper-unity/wiki/Avoid-null-comparisons-against-UnityEngine.Object-subclasses
https://subscription.packtpub.com/book/game+development/9781785884580/2/ch02lvl1sec23/faster-gameobject-null-reference-checks