MonoBehaviourからTransformを参照する処理時間比較してみる
【検証環境】
・Unity5.2.4f1(Personal Edition)
・Nexus7(Android 5.0.2)
・10万回参照した際にかかった時間を比較
【比較項目】
①キャッシュされたメンバ
②通常
③GetComponent(ジェネリック)
④GetComponent(データ型)
⑤GetComponent(文字列)
⑥NGUI式キャッシュプロパティ
⑦ifでのnullチェック
⑧null合体演算子でのnullチェック
【テストコード】
using UnityEngine;
public class Test : MonoBehaviour {
Transform trans_ = null;
Transform cachedTransform { get { if (this.trans_ == null) this.trans_ = this.transform; return this.trans_; } }
void Start () {
int count = 100000;
float prevTime, nowTime;
Transform tr;
this.trans_ = this.transform;
// ①
prevTime = Time.realtimeSinceStartup;
for (int i = 0; i < count; ++i) {
tr = this.trans_;
}
nowTime = Time.realtimeSinceStartup;
Debug.LogError("① this.trans_ : " + (nowTime-prevTime));
// ②
prevTime = Time.realtimeSinceStartup;
for (int i = 0; i < count; ++i) {
tr = this.transform;
}
nowTime = Time.realtimeSinceStartup;
Debug.LogError("② this.transform : " + (nowTime-prevTime));
// ③
prevTime = Time.realtimeSinceStartup;
for (int i = 0; i < count; ++i) {
tr = this.GetComponent<Transform>();
}
nowTime = Time.realtimeSinceStartup;
Debug.LogError("③ GetComponent<> : " + (nowTime-prevTime));
// ④
prevTime = Time.realtimeSinceStartup;
for (int i = 0; i < count; ++i) {
tr = this.GetComponent(typeof(Transform)) as Transform;
}
nowTime = Time.realtimeSinceStartup;
Debug.LogError("④ GetComponent(typeof) : " + (nowTime-prevTime));
// ⑤
prevTime = Time.realtimeSinceStartup;
for (int i = 0; i < count; ++i) {
tr = this.GetComponent("Transform") as Transform;
}
nowTime = Time.realtimeSinceStartup;
Debug.LogError("⑤ GetComponent(\"\") : " + (nowTime-prevTime));
// ⑥
prevTime = Time.realtimeSinceStartup;
for (int i = 0; i < count; ++i) {
tr = this.cachedTransform;
}
nowTime = Time.realtimeSinceStartup;
Debug.LogError("⑥ cachedTransform : " + (nowTime-prevTime));
// ⑦
prevTime = Time.realtimeSinceStartup;
for (int i = 0; i < count; ++i) {
if (this.trans_ == null)
this.trans_ = this.transform;
tr = this.trans_;
}
nowTime = Time.realtimeSinceStartup;
Debug.LogError("⑦ if : " + (nowTime-prevTime));
// ⑧
prevTime = Time.realtimeSinceStartup;
for (int i = 0; i < count; ++i) {
tr = this.trans_ ?? (this.trans_ = this.transform);
}
nowTime = Time.realtimeSinceStartup;
Debug.LogError("⑧ ?? : " + (nowTime-prevTime));
}
}
【結果】
① this.trans_ : 0.0003967285
② this.transform : 0.008666992
③ GetComponent<> : 0.01818848
④ GetComponent(typeof) : 0.03417969
⑤ GetComponent("") : 1.000092
⑥ cachedTransform : 0.005523682
⑦ if : 0.004394531
⑧ ?? : 0.0007324219
【まとめ】
「Transformはキャッシュすれば早い」というのは公式でも言われている通り。
NGUIで良く見るcahcedTransformは確かに効果が見られるが
UnityEditor上だと通常参照の速度が速くなっていて効果がなくなっていた。
通常参照速度はPlatform毎でそんなに違うのだろうか・・・?
またifによるnullチェックはよく言われている通りDestroyチェックが走るようなのでコストが高い。
null合体演算子はDestroyチェックが走らないので早いが使いどころは難しい。
GetComponentでTransformを参照することはまずないが比較すると倍ぐらい遅い。
セキュアか速度かのトレードオフをどこでとるかでキャッシュの設計は変わってくるだろう。
正直Transformのキャッシュにこだわるぐらいなら
文字列操作などのボトルネックになりやすい箇所を見直した方が恩恵は大きいと思う。