Search Unity

Question Why is GetComponent<T>() is more efficient than GetComponent(T) ?

Discussion in 'Scripting' started by unity_A6665FBD939D91D95BAE, Feb 27, 2024.

  1. unity_A6665FBD939D91D95BAE

    unity_A6665FBD939D91D95BAE

    Joined:
    Dec 12, 2023
    Posts:
    6
    From https://docs.unity3d.com/ScriptReference/GameObject.GetComponent.html, it said that GetComponent<T>() is more efficient than the GetComponent(T) version, it even said to use GetComponent(T) only if necessary which imply that it is very bad on performance. But, why ? How does GetComponent implemented in unity which caused the generic version to be faster ?
     
  2. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,975
    No, that is not implied. Efficiency is not only about performance. Also the docs said "not as efficient" which does not imply very bad. The generic version is simply shorter to write as you don't need to use typeof and you don't need to type cast the result. So you can use the returned instance immediately.

    In the past the generic version was just a wrapper for the non-generic version which did the typeof and the cast inside that method. So technically it was even a bit slower. However the current implementation uses a cast helper struct to avoid the cast all together. In this implementation the native Unity code directly sets the reference in that struct without any additional type checks. So it might be a tiny bit faster compared to doing the cast manually on the managed side. However this is a tiny difference. The generic version is mainly there for convenience and to avoid some mistakes as you only provide the type once.
     
  3. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,808
    "not as efficient"

    This can mean anything from 0.1% more resource intensive, to infinitely more resource intensive. It does NOT indicate "performance", it says "efficient". This could also imply that it's mainly using less memory or creates less garbage.

    In addition, this may hold only true for the Unity editor version for which this part of the manual was written, since such statements are not consistently updated.

    Therefore: measure! ;)
     
  4. Nad_B

    Nad_B

    Joined:
    Aug 1, 2021
    Posts:
    702
    I think under the hood,
    GetComponent<T>()
    just calls
    GetComponent(typeof(T))
    , so technically GetComponent(Type) should be "faster" (by faster here I mean by an unmeasurable amount of times, unless called millions of times in a row...)
     
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,797
    And both are slower than
    TryGetComponent(out T)
    .
     
    Nad_B likes this.
  6. unity_A6665FBD939D91D95BAE

    unity_A6665FBD939D91D95BAE

    Joined:
    Dec 12, 2023
    Posts:
    6
    Ok thank you everyone for the answer

    If there is really only tiny difference, then unity documentation is just being too dramatic by saying to use it only if necessary, unless there is an actual case where that tiny difference become a big difference.

    Correct me if i'm wrong, but in the implementation you linked, GetComponent<T>() will call extern function GetComponentFastPath while GetComponent(T) is an extern function. Is there any actual difference between GetComponentFastPath and GetComponent(T) or they are the same under the hood?
     
  7. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    459
    I think you're hanging onto the wrong thing here: that there would be advantage here which could make up for a lazy architecture.
    What Unity scripters should take away from
    GetComponent
    is
    - to avoid it wherever it is possible
    - if you can't avoid it on any way, cache the result if possible, so next call won't be a
    GetComponent

    - use
    TryGetComponent
    instead of explicit null-check

    You save much more resources if you don't call it or you cache it than you gain anything switching between the two types of
    GetComponent
    methods.
     
    Ryiah and Bunny83 like this.
  8. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,975
    There are really only rare usecases where you may use the non generic version of GetComponent. Those cases would all have to do with some dynamic gathering of components where you got the System.Type object through other means. For example when you do something like deserialization. Though in that case you usually use AddComponent. GetComponent may also be used when you create some custom animation system and you need to get a binding dynamically.

    In the majority of cases you would use the generic version. It works with interfaces as well and you don't have to do any explicit casting. That's the main point. Casting in .NET requires the runtime to do a type check. Unity's implementation does not require a type check as the conversion is done implicitly, essentially through native unsafe code. Though since the native implementation is asked for a specific type, the implicit unsafe cast is essentially safe.

    The extra method call doesn't really matter. The type cast is more important. Just to be clear, in the past the generic version looked like this:

    Code (CSharp):
    1. public T GetComponent<T>() where T : Component
    2. {
    3.     return (T)GetComponent(typeof(T));
    4. }
    Back then this was only for convenience as it still required a cast on the managed side (GetComponent returns a UnityEngine.Object) and this implementation also was constraint on Component. So you couldn't ues interfaces with this implementation, now you can.
     
    CodeRonnie, Ryiah and Lurking-Ninja like this.
  9. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,114
    I was curious when this happened as I couldn't remember, and after poking the chatbot came up with Unity 5.0.

    https://unity.com/releases/editor/whats-new/5.0.0
     
    Bunny83 and Lurking-Ninja like this.
  10. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,975
    Note that even before Unity 5 GetComponent could be used with interfaces, but not the generic version. Even version 2.6 did support interfaces (which was the first version I actually used something like 13 years ago ^^).

    Yes time is passing way too fast considering version 5 is now 9 years old :)