赞
踩
先给出一组测试数据,分别用三种比较方式进行100万次UnityEngine.Object的判空。
比较方式 | 耗时(毫秒) |
---|---|
obj == null | 43 |
obj is null | 4 |
System.Object.ReferenceEquals(obj, null) | 4 |
一开始的时候用GameObject和继承MonoBehaviour组件拿到的测试结果不一样,GameObject用ReferenceEquals或者 is null比较速度只能提升一倍,后来发现是忘记缓存gameObject了(在MonoBehaviour脚本里直接写的gameobject是一个属性,虽然一般不会造成性能问题,但在测试时不加注意可能会得到错误的结论)。
拿到这个数据后就可以开始猜测了,is null就是一个语法糖,通过上述数据可以猜测is null 会被翻译成ReferenceEquals。那么ReferenceEquals为什么会快这么多呢。
既然ReferenceEquals要快这么多,那就去看一下实现,不看不要紧,一看吓一跳,这不就是 == 么。一开始还怀疑是不是上面加的两个特性捣的鬼,查了一下排除了。
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[System.Runtime.Versioning.NonVersionable]
public static bool ReferenceEquals (Object objA, Object objB) {
return objA == objB;
}
那么会不会是函数参数是system.object造成的呢,于是增加两种比较方式得到以下结果
比较方式 | 耗时(毫秒) |
---|---|
obj == null | 43 |
obj is null | 4 |
(object)obj == (object)null | 4 |
SelfEquals(obj, null) | 9 |
SelfEquals实现如下
bool SelfEquals(object obj1, object obj2)
{
return obj1 == obj2;
}
到这里事情就有点意思了,到这时可以暂时理解为把UnityEngine.Object转成System.Object比较会快一些。自己写SelfEquals慢一点估计是因为多了一层函数调用。
最后用ILSpy反编译一下unity生成的dll,发现直接使用==时,编译器翻译的最终c#代码是这样的
if ((Object)(object)obj == (Object)null){}
而其它几种都是这样的
if (obj == null){}
如果比较的不是UnityEngine.Object,而是继承自System.Object的类的话则最终翻译到的c#代码都是第二种情况。
unity有三大内存域,跨域的通信过渡会造成性能上的损失,由于UnityEngine.Object的数据是保存在本地域上,直接使用 == 时可能会引发本地域和托管域之间的桥梁通信过度,从而造成速度变慢。而把他们当作System.Object做比较时,应该是只在托管域中做了一次引用比较。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。