(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]


本ブログの運営者kan.kikuchiが個人で開発したゲームです!

    

enumのToStringが遅いって本当ですか?【C#】【Unity】【拡張メソッド】【最適化】


このエントリーをはてなブックマークに追加



この記事でのバージョン
Unity 5.6.1f1


はじめに

enumのToStringは遅いという話を耳にしたので、気になって調べてみた系の記事です!

ちなみに、以前にenumをkeyにしたDictionaryが遅いという話も記事にしてました。



そもそものenumのToStringは遅いという由来は以下の通り。

EnumのToStringは非常に遅いです。
これは内部ではリフレクションを使用しているためです。


上記の記事によると、ToStringに代わる拡張メソッドをswitch文で実装する事で

なんと約100倍ものスピードになるそうです!


という事で実際にUnityで確かめてみました!


計測

計測したコードは以下の通りで、TestEnumというenumとそれを拡張するTestEnumEx、

さらにswitch文で実装した拡張メソッドToStringQuicklyを作成し、

ToStringとToStringQuicklyのそれぞれを一定回数実行した時の処理時間を計測している感じです。


なお、計測には以前紹介したProcessTimerを使用しました。

using UnityEngine;


//計測テスト用Enum
public enum TestEnum{
  Test1, Test2, Test3
}

public class NewBehaviourScript : MonoBehaviour {


  private void Start () {

    //処理回数
    int loopCount = 1000000;

    //普通のToStringの時間を計測
    ProcessTimer.Restart (); 

    for (int i = 0; i < loopCount; i++) {
      TestEnum.Test1.ToString();
    }

    Debug.Log(ProcessTimer.Stop ());


    //拡張メソッドのToStringの時間を計測
    ProcessTimer.Restart (); 

    for (int i = 0; i < loopCount; i++) {
      TestEnum.Test1.ToStringQuickly();
    }

    Debug.Log(ProcessTimer.Stop ());

  }


}

//TestEnumの拡張クラス
static class TestEnumEx{
  //高速でstringに変換する拡張メソッド
  public static string ToStringQuickly(this TestEnum testEnum){

    //各enumごとにstringを返す
    switch (testEnum){
      case TestEnum.Test1: return "Test1";
      case TestEnum.Test2: return "Test2";
      case TestEnum.Test3: return "Test3";

      default:{
          Debug.LogError(testEnum.ToString() + "のstringが設定されていません!");
          return testEnum.ToString();
      }

    }

  }
}


気になる結果は以下の通りです。

処理回数 ToString ToStringQuickly
100 0.000695 0.000120
10000 0.024523 0.000319
1000000 1.928718 0.019580


enumのToStringが遅いって本当ですね!


ただし、100回程度であればほぼ誤差のような値なので、

よっぽどの事がない限り気にしなくていいような感じですかね。


とは言え、遅いと知っていて使うのと、

知らずに使うでは、だいぶ違うと思うので良い勉強になりました。


実機

と、終わる予定でしたが、

よくよく考えて見ると我らが使っているのはUnityです。


そう、iPhoneなどの実機に書き出す時はIL2CPPを使って書き出しているので、

C#じゃなくてC++で動作しています。


ちなみにIL2CPPとは以下のようなものらしいです。

IL2CPP スクリプティングバックエンドは Unity プロジェクトにあるスクリプト、アセンブリからなる IL コードをC++ コードに変換します。


もし、IL2CPPがenum部分をいい感じに変換してくれていたら、早くなるのでは!

という事で、先ほどのコードをiPhone6s+で動かしてみました!

処理回数 ToString ToStringQuickly
1000000 2.663367 0.003836


むしろ実機の方が差が開いている……(´・ω・`)


おわりに

enumのToStringが遅いという事、

switch文で実装した拡張メソッドを用いる事で高速化できる事は分かったんですが、

さすがに全enumの拡張メソッドを作るのは面倒ですよね……。


そんな場合はILGeneratorやExpressionTreeを使って汎用的な処理を作る方法があるみたいです。




もしくはUnityと言えばエディタ拡張と言う事で、

エディタ拡張で拡張メソッドの自動作成&更新でなんとかできるかも……?(やる予定はありません)