こんにちは、Unityエンジニアのオオバです。
C#を使う上でLINQは非常に便利な機能なのは言うまでもありません。
しかし、実際のプロダクトへ組み込む際の負荷は知っておくべきということで、改めて調べてみたという記事です。
今回の検証対象は使用頻度が高いフィルタ系関数です。
- FirstOrDefault
- Any
- Where
検証するポイントはUnityProfiler項目で言うと、Time ms(実行時間)
とGC Alloc
です。
実行時間は言葉の通りで、高ければ高いほどFPSが低下します。
GC Allocは1フレームにヒープメモリの確保メモリ容量で、数値が高いとGC発生回数が増えてしまい、プロダクトのパフォーマンスを下げる場合があります。
今回の検証では数値を可視化しやすいように配列要素数を10000個
、1フレーム内の実行回数を100回
とします。
検証方法は以前ブログで紹介したやり方です。
確認場所(for, foreach文など)にProfiler.BeginSampleとProfiler.EndSampleで処理を挟んで数値を確認しています。
FirstOrDefaultの場合
Anyの場合
Whereの場合
for文の場合
これらの結果を以下の表にまとめます。
処理名 | 処理時間 | GC Alloc |
---|---|---|
FirstOrDefault | 97.52ms | 13.3KB |
Any | 97.52ms | 13.3KB |
Where | 0.05ms | 17.2KB |
配列のfor文 | 5.17ms | 0KB |
IList型のfor文 | 19.52ms | 0KB |
List型のfor文 | 16.65ms | 0KB |
配列foreach | 5.69ms | 0KB |
List型のforeach | 42.15ms | 0KB |
IList型宣言変数のforeach | 43.34ms | 3.9KB |
IEnumerable型のforeach | 101.81ms | 10.9KB |
FirstOrDefault
、Any
、IEnumerable型のforeach文
は配列for文
、配列foreach文
の約20倍の処理負荷配列for文
、配列foreach文
が最速- LINQ処理は軒並みGC Allocを消費する
for文
、配列・Listのforeach文
はGC Allocを消費しないIList型宣言変数のforeach
はGCAllocを消費するListのfor文
はListのforeach文
より2.5倍早い
まとめ
予想通りパフォーマンスだけで言うと、ベタにfor文で書いた方が早いですし、GC対策にもヒットしますが記述コード量の削減、可読性を考えるとLINQは捨て難いものです。
今回の検証コード自体が、可視化するために非現実で高い負荷をかけています。for文がLINQの20倍早いとはいえ、ループ回数や使用頻度が低ければ、それは全く問題にならないという事になります。
LINQとfor文の使い分けとして今回のような毎フレーム実行する部分でのLINQ使用は控えるべきだとオオバは考えます。あっという間にGC発生させることになるからです。
高頻度処理には素直にfor文が良いかと。
何事も使い所が重要で、どの処理にどれだけのリソースを使うかという情報は把握しておきたいものです。
この記事が気に入ったらフォローしよう