A*経路探索のコードを書いていてListの最小値を取得する最速の方法が気になったので検証してみました。
前回、速度比較のやり方を模索してみたのはこの為だったりします。
for文 vs Min()
普通にfor文で全要素を一つづつ比較していくのとlinqのMin()を使うのではどっちが速いんでしょうか?
コードは以下です。
0~100000のランダムな整数の入った要素数10万のListを宣言してその中から最小値を取得、
Profiler.BeginSample/EndSampleで、最小値を取得する部分だけを計測しています。
public class MinTest {
//for文のやつ
[Test]
public void UseFor() {
var randamValues = GetRandamValues();
Profiler.BeginSample("MinTest.UseFor");
var min = randamValues[0];
for (int i = 1; i < randamValues.Count; i++) {
min = randamValues[i] < min ? randamValues[i] : min;
}
Profiler.EndSample();
Debug.Log(min);
}
//Min()
[Test]
public void UseMin() {
var randamValues = GetRandamValues();
Profiler.BeginSample("MinTest.UseListMin");
var min = randamValues.Min();
Profiler.EndSample();
Debug.Log(min);
}
List<int> GetRandamValues() {
var randamValues = new List<int>();
for (int i = 0; i < 100000; i++) {
randamValues.Add(Random.Range(0, 100000));
}
return randamValues;
}
}
結果
GC Alloc | Time | |
---|---|---|
UseFor | 0B | 1.18ms |
UseMin | 40B | 1.49ms |
速度には気にするほどの差は出ませんが、Min()はGC Allocが発生してしまいますね。
条件分岐の書き方で差は出るの?
やっぱり普通にfor文使うのが速いですね。
しかし、もう一つ気になることがあります。
条件分岐の書き方で差が出るかどうかです。
//for文のやつ
[Test]
public void UseFor() {
var randamValues = GetRandamValues();
Profiler.BeginSample("MinTest.UseFor");
var min = randamValues[0];
for (int i = 1; i < randamValues.Count; i++) {
min = randamValues[i] < min ? randamValues[i] : min;//←ここの書き方で差は出るの?
}
Profiler.EndSample();
Debug.Log(min);
}
以下の3つを試してみます
①if文
if (randamValues[i] < min) min = randamValues[i];
②条件演算子
min = randamValues[i] < min ? randamValues[i] : min;
③条件演算子(条件式を反転)
min = randamValues[i] >= min ? min : randamValues[i];
結果
誤差で結果が上下するので、1000回の平均を計測しました。
微妙に差が出ますが、気にするレベルではないですね。
GC Alloc | Time | |
---|---|---|
①if文 | 0B | 1.28120ms |
②条件演算子 | 0B | 1.26898ms |
③条件演算子(条件式を反転) | 0B | 1.24765ms |
まとめ
普通にfor文使うのが速いしGC Allocも発生しない!
ご意見ご感想、多分これが一番速いと思います等ありましたらコメントを頂けますと幸いです!