コガネブログ

平日更新を目標にUnityやC#などのゲーム開発アレコレを書いていきます

【Unity】GameObject.Find 系関数の処理速度の検証結果

検証結果

※結果は Unity エディタ上で 10 回テストしたものの平均値、単位は秒
※Unityのバージョンは4.3.4

オブジェクト数 検索方法 1,000 回実行 10,000 回実行 100,000 回実行
100 Find 0.004392 秒 0.027789 秒 0.252738 秒
100 FindGameObjectWithTag 0.000693 秒 0.004147 秒 0.018733 秒
100 FindObjectOfType 0.070080 秒 0.622304 秒 5.801984 秒
1,000 Find 0.037534 秒 0.357311 秒 3.543825 秒
1,000 FindGameObjectWithTag 0.000655 秒 0.002315 秒 0.018519 秒
1,000 FindObjectOfType 0.157907 秒 1.552248 秒 16.20919 秒
10,000 Find 0.429361 秒 4.274960 秒 42.64132 秒
10,000 FindGameObjectWithTag 0.000346 秒 0.001686 秒 0.016235 秒
10,000 FindObjectOfType 1.375987 秒 14.24521 秒 長いので省略

まとめ

Find 関数と FindObjectOfType 関数は
オブジェクト数や検索回数に比例して遅くなりました

特に FindObjectOfType 関数は全ゲームオブジェクトの
コンポーネントを検索するためかとても遅かったです

FindGameObjectWithTag 関数は
オブジェクト数や検索回数が増えたとしてもとても高速でした

なので、ゲームオブジェクトの検索速度がボトルネックになった場合は
検索方法をタグによる検索にすると処理速度が改善するようです

検証用スクリプト

using System;
using UnityEngine;

/// <summary>
/// Find 関数の処理速度を計測するスクリプト
/// </summary>
public sealed class FindTest : MonoBehaviour
{
    public int LoopCount        = 1000; // 1 回のテストで Find 関数を実行する回数
    public int TestCount        = 10;   // テストの回数
    public int NumGameObjects   = 100;  // 検索対象のオブジェクトの数
    
    /// <summary>
    /// ゲーム開始時に指定された数分のオブジェクトを生成します
    /// </summary>
    private void Awake()
    {
        var types = new PrimitiveType[]
        {
            PrimitiveType.Capsule, 
            PrimitiveType.Cube,             
            PrimitiveType.Cylinder, 
            PrimitiveType.Plane, 
            PrimitiveType.Quad,             
            PrimitiveType.Sphere, 
        };

        for (int i = 0; i < NumGameObjects; i++)
        {
            GameObject.CreatePrimitive(types[UnityEngine.Random.Range(0, types.Length)]);
        }
    }

    /// <summary>
    /// Find, FindGameObjectWithTag, FindObjectOfType 関数を実行するボタンを表示します
    /// </summary>
    private void OnGUI()
    {
        DrawButton(0,   "Find",                     () => GameObject.Find("Player")                     );
        DrawButton(100, "FindGameObjectWithTag",    () => GameObject.FindGameObjectWithTag("Player")    );
        DrawButton(200, "FindObjectOfType",         () => GameObject.FindObjectOfType<BoxCollider>()    );
    }
    
    /// <summary>
    /// 指定された関数を実行するボタンを表示します
    /// </summary>
    private void DrawButton(float buttonY, string buttonText, Action findAct)
    {
        if (GUI.Button(new Rect(0, buttonY, Screen.width, 100), buttonText))
        {
            var sum = 0f;
            for (int i = 0; i < TestCount; i++)
            {
                var time = Time.realtimeSinceStartup;
                for (int j = 0; j < LoopCount; j++)
                {
                    findAct();
                }
                time = Time.realtimeSinceStartup - time;
                sum += time;
            }
            var avg = sum / TestCount;
            Debug.Log(avg);
        }
    }
}