ScriptableObject とそれ以外のパフォーマンス比較
調査内容
下記のような ScriptableObject や struct に対しデータの読み込み速度を測ってみた。
public class TestScriptableObject : ScriptableObject { public string[] stringValue; public int[] intValue; public float[] floatValue; }
public struct TestStruct{ public string[] stringValue; public int[] intValue; public float[] floatValue; }
Unity のバージョンは 2017.3.1f1。 デバイスは ZenPad3 8.0 Z581KL 。
結果
// ハードコーディング // PFS=36 for ( var i = 0; i < 2000; ++i ){ var data = ScriptableObject.CreateInstance< TestScriptableObject >(); data.stringValue = new string [ 10 ]; for ( var n = 0; n < data.stringValue.Length; ++n ) data.stringValue[ n ] = "Hello"; data.intValue = new int [ 10 ]; for ( var n = 0; n < data.intValue.Length; ++n ) data.intValue[ n ] = 1; data.floatValue = new float [ 10 ]; for ( var n = 0; n < data.floatValue.Length; ++n ) data.floatValue[ n ] = 9.8f; }
// ScriptableObject // PFS=14 for ( var n = 0; n < 2000; ++n ){ var data = Resources.Load( "ScriptableObject/TestScriptableObject" ) as TestScriptableObject; Resources.UnloadAsset( data ); }
// Text // PFS=8 for ( var i = 0; i < 2000; ++i ){ var text = Resources.Load( "ScriptableObject/TestText" ) as TextAsset; var separator = new char []{ '\n' }; var strings = text.text.Split( separator ); Resources.UnloadAsset( text ); var data = new TestStruct(); var index = 0; var length = 0; length = int.Parse( strings[ index++ ] ); data.stringValue = new string [ length ]; for ( var n = 0; n < data.stringValue.Length; ++n ) data.stringValue[ n ] = strings[ index++ ]; length = int.Parse( strings[ index++ ] ); data.intValue = new int [ length ]; for ( var n = 0; n < data.intValue.Length; ++n ) data.intValue[ n ] = int.Parse( strings[ index++ ] ); length = int.Parse( strings[ index++ ] ); data.floatValue = new float [ length ]; for ( var n = 0; n < data.floatValue.Length; ++n ) data.floatValue[ n ] = float.Parse( strings[ index++ ] ); }
// Binary // PFS=13 for ( var i = 0; i < 2000; ++i ){ var text = Resources.Load( "ScriptableObject/TestBin" ) as TextAsset; using( var fos = new MemoryStream( text.bytes ) ){ using ( var reader = new BinaryReader( fos ) ){ var data = new TestStruct(); var length = 0; length = reader.ReadInt32(); data.stringValue = new string [ length ]; for ( var n = 0; n < data.stringValue.Length; ++n ) data.stringValue[ n ] = reader.ReadString(); length = reader.ReadInt32(); data.intValue = new int [ length ]; for ( var n = 0; n < data.intValue.Length; ++n ) data.intValue[ n ] = reader.ReadInt32(); length = reader.ReadInt32(); data.floatValue = new float [ length ]; for ( var n = 0; n < data.floatValue.Length; ++n ) data.floatValue[ n ] = reader.ReadSingle(); } } Resources.UnloadAsset( text ); }
まとめ
1.ハードコーディング(FPS=36) 2.ScriptableObject(FPS=14) 3.バイナリ読み込み(FPS=13) 4.テキスト読み込み(FPS=8)
実測してみると ScriptableObject が優秀だと分かった。
バイナリ読み込みは速度が出るけど自力でパースする手間がある。 テキスト読み込みはちょっと遅い。
開発初期は XML, JSON, CSV でデータを用意し、ある程度データ形式が固まってきたらパフォーマンスが気になるところを ScriptableObject に変えていくとかが現実的な使い方かもしれない。
※XML, JSON, CSV は Editor ディレクトリに入れてエディタ拡張で ScriptableObject に変換。