Unity中直接使用transform和gameObject的效率測試,unitygameobject
盡信書不如無書,更何況是網上開發人員的部落格。這裡也包含我自己的部落格,有的時候回過頭來看是有錯誤的地方,但是我也懶得改了,而且很多時候我們看到的文章還不一定是原始地址,而是被各個網站七轉八轉的,更加不可能保證準確性。
這裡測試了這麼一個說法:“不要在指令碼中直接使用transform或者gameObject,而應該在一開始緩衝成成員變數如_transform和_gameObject來訪問。因為前者每次執行的時候都要擷取對應的組件,效率低。”
這種說法不能說完全是錯誤的,但是經過自己的測試明白其原理後,會對這個問題以及與其類似的問題都會有更加清晰的瞭解。
首先我們使用組件的時候盡量在一開始使用GetComponent緩衝到成員變數裡面,這個是完全合理的。但是tansform和gameObject如此常用的對象,Unity應該有更好的最佳化才對。否則就顯得太低級了。我測試的結果也確實如此。如果不想看後面的分析,直接看結論就好了。
結論:Unity中直接存取transform效率會比緩衝成成員變數慢一點點,這個只有量級非常大的時候才會體現出來。 Unity對transform和gameObject有足夠的最佳化處理,不要自己再類比Unity寫屬性來處理,多數情況效率更差。
請看:
測試代碼是一個簡單的transform座標賦值,迴圈100w次。
其中Unity屬性就是直接存取transform的時間消耗,而緩衝的變數就是成員變數版本的。可以看到直接緩衝成員變數確實會快一些,但是100w次執行,效能差別也就10%左右。個人感覺這點差別影響不大。是直接使用unity的屬性,還是緩衝成員變數看個人習慣了。
注意後面兩個屬性進行判斷和屬性直接擷取變數。我們有可能會“自以為是”的這麼寫,如果_transform為空白,則擷取對應組件,否則直接返回成員變數。這種情況就是最慢的“屬性進行判斷”,這個時候屬性會執行相對複雜的邏輯,速度慢就合情合理了。而如果屬性直接返回成員變數,其效率是跟直接存取成員變數一致的。
測試代碼如下:
using UnityEngine;using System.Collections;public class TestTransform : MonoBehaviour { private GameObject _go; private Transform _tr; protected Transform SimpleTr { get { return _tr; } } protected Transform Tr { get { if (_tr == null) { _tr = transform; } return _tr; } } protected GameObject SimpleGo { get { return _go; } } protected GameObject Go { get { if (_go == null) { _go = gameObject; } return _go; } }void Start () { _go = gameObject; _tr = transform; DoTestTransform(); DoTestGameObject(); } public void DoTestTransform() { int count = 1000000; transform.position = Vector3.zero; int time = System.Environment.TickCount; for (int i = 0; i < count; ++i) { int index = i % 100; transform.position = Vector3.one * index; } Debug.Log("Unity屬性: " + (System.Environment.TickCount - time) * 1000); _tr.position = Vector3.zero; int time2 = System.Environment.TickCount; for (int i = 0; i < count; ++i) { int index = i % 100; _tr.position = Vector3.one * index; } Debug.Log("緩衝的變數: " + (System.Environment.TickCount - time2) * 1000); Tr.position = Vector3.zero; int time3 = System.Environment.TickCount; for (int i = 0; i < count; ++i) { int index = i % 100; Tr.position = Vector3.one * index; } Debug.Log("屬性進行判斷:" + (System.Environment.TickCount - time3) * 1000); SimpleTr.position = Vector3.zero; int time4 = System.Environment.TickCount; for (int i = 0; i < count; ++i) { int index = i % 100; SimpleTr.position = Vector3.one * index; } Debug.Log("屬性直接擷取變數: " + (System.Environment.TickCount - time4) * 1000); } public void DoTestGameObject() { int count = 1000000; gameObject.transform.position = Vector3.zero; int time = System.Environment.TickCount; for (int i = 0; i < count; ++i) { int index = i % 100; gameObject.transform.position = Vector3.one * index; } Debug.Log("Unity屬性: " + (System.Environment.TickCount - time) * 1000); _go.transform.position = Vector3.zero; int time2 = System.Environment.TickCount; for (int i = 0; i < count; ++i) { int index = i % 100; _go.transform.position = Vector3.one * index; } Debug.Log("緩衝的變數: " + (System.Environment.TickCount - time2) * 1000); Go.transform.position = Vector3.zero; int time3 = System.Environment.TickCount; for (int i = 0; i < count; ++i) { int index = i % 100; Go.transform.position = Vector3.one * index; } Debug.Log("屬性進行判斷:" + (System.Environment.TickCount - time3) * 1000); SimpleGo.transform.position = Vector3.zero; int time4 = System.Environment.TickCount; for (int i = 0; i < count; ++i) { int index = i % 100; SimpleGo.transform.position = Vector3.one * index; } Debug.Log("屬性直接擷取變數: " + (System.Environment.TickCount - time4) * 1000); }}