今回のエンジニアブログを担当する加賀です。
UnityでC#のLINQを使っているとき、
何度もメソッド呼び出しがされるので速度が遅くなるのではないか?
という疑問が出来たので、計測してみました。
計測環境
- Mac OS X 10.9.5
- Intel Core i5 1.3GHz
- Unity 5.1.2
基本コード
ランダムな0~999までの10,000,000個の整数の中から、ランダムな値が何個あるかをカウントする処理です。
なお、生成される乱数の順序を同じにするために、seed値を指定しています。
100回計算して、最小と最大の値を除いた98回の平均値を時間とします。
以下のCalcTime関数の中身を変えて計測してみます。
public class Test : MonoBehaviour { List<int> list; bool isFinish; void Start() { isFinish = false; list = new List<int> (); UnityEngine.Random.seed = 12345; for(int i = 0; i < 10000000; i++) { list.Add (UnityEngine.Random.Range (0, 1000)); } } void Update() { if (!isFinish) { List<int> time = new List<int> (); for (int i = 0; i < 100; i++) { DateTime start = DateTime.Now; CalcTime (); DateTime end = DateTime.Now; TimeSpan span = end - start; time.Add (span.Milliseconds); } int min = time.Min (); time.Remove (min); int max = time.Max (); time.Remove (max); double avg = time.Average (); Debug.Log ("min:" + min + " max:" + max + " avg:" + avg); isFinish = true; } } void CalcTime() { int count = 0; int search = UnityEngine.Random.Range (0, 1000); // ここ以下を変えます } }
for文(参考)
int listSize = list.Count; for (int i = 0; i < listSize; i++) { if (list[i] == search) { count++; } }
foreach文
foreach (int val in list) { if (val == search) { count++; } }
foreach文と同等なコード
var e = list.GetEnumerator (); while (e.MoveNext ()) { if (e.Current == search) { count++; } }
ラムダ式
count = list.Count (val => val == search);
一旦delegate変数に入れたラムダ式
Func<int, bool> func = val => val == search; count = list.Count (func);
測定結果
処理方法 | 結果(ミリ秒) | 5回平均(ミリ秒) |
---|---|---|
for文(参考) | 172.1122448979592 | |
foreach文 | 457.5408163265306 | |
foreach文と 同等なコード |
441.4469387755102 | |
ラムダ式 | 615.369387755102 | |
一旦delegate変数に 入れたラムダ式 |
607.304081632653 |
結果から
for文は安全性を犠牲に速度を優先しているのであまり比較対象には出来ませんが、
foreach文で自力で実装するのと、LINQを使用するのとで結構な差が出ることがわかりました。
UnityのLINQ実装は公開されているので、内部コードと自力実装のforeach文とを見比べてみると、
引数のnullチェック関数やセレクター(今回はカウント対象かどうかの判定関数)の呼び出しで時間がかかっていると思います。
ラムダ式をデリゲート変数に入れても、無視できる差しか縮まらないのを見ても、関数呼び出しが重い処理というのがわかります。
iOSでの制約で出来ない場合もありますが、同じことを複数のLINQメソッドで記述するよりも、
出来る限りLINQメソッドをまとめた方が早くなることがわかりました。
LINQはやりたい事が簡潔に記述できて便利ですが、よく気をつけて使用していきたいと思います。