TryGetComponent() と比べたら GetComponent() を使う理由がなくなった件
Unity2019.2 から GetComponent() とほぼ同機能の TryGetComponent() が追加されています。
文法的な差異くらいなのかなと軽くスルーしてたのですが、
TryGetComponent() は alloc しない
という違いがあるらしいです。
(正確には、エディタ上で対象のコンポーネントがなかったときだけ GetComponent() は alloc する[1])
となると、あとはパフォーマンスが気になるところです。
パフォーマンス比較
次のようなコードで1000個の GameObject からコンポーネントを取得してみました。
環境は Unity2021.3.2f1、Win10 です。
void Profile_GetComponent()
{
Profiler.BeginSample(nameof(Profile_GetComponent));
for (var i = 0; i < count; ++i)
{
var sampleComponent = _goList[i].GetComponent<SampleComponent>();
if (sampleComponent != null)
{
sampleComponent.value++;
}
}
Profiler.EndSample();
}
void Profile_TryGetComponent()
{
Profiler.BeginSample(nameof(Profile_TryGetComponent));
for (var i = 0; i < count; ++i)
{
if (_goList[i].TryGetComponent<SampleComponent>(out var sampleComponent))
{
sampleComponent.value++;
}
}
Profiler.EndSample();
}
結果はこちら
コンポーネント有りエディター
コンポーネント有りビルド後
コンポーネント無しエディター
コンポーネント無しビルド後
TryGetComponent() のほうがちょっと速い!
たしかに「コンポーネント無しエディター」で GC Alloc がなく劇的に速い!
というわけで
GetComponent() を使う理由がなくなった気がするので常に TryGetComponent() で良いかなと思いました。
とはいえ GetComponent() をそんなにぶん回すこともないと思うので、パフォーマンスが気になる部分でなければどちらでもいい気もします。コンポーネントが確実にある想定なら GetComponent()、無いケースも想定してるなら TryGetCompoenent()、みたいな意味付けもありかもしれません。
ちなみに
パフォーマンスについてググったところテラシュールブログさんの記事にたどり着いたのですが、
よく見ると「コンポーネント無しエディター」の TryGetCompoenent()でも GC Alloc が発生していてドキュメントの記述と異なるのが気になりました。
もしかしたら当時と今の Unity で挙動が異なってるかもと思い、上記実験をしてみました。
実験内容を思いっきり参考にさせていただきました。感謝。
参考
-
The notable difference compared to GameObject.GetComponent is that this method does not allocate in the editor when the requested component does not exist.
https://docs.unity3d.com/ja/current/ScriptReference/GameObject.TryGetComponent.html
Discussion