Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Most performing way to access elements?

Discussion in 'Scripting' started by rapidrunner, Mar 6, 2016.

  1. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944
    I am looking for a performing way to use these elements (most are text field).

    So far I understand that in Unity; the GetComponent is " less expensive" than GameObject.Find or Transform.Find; and beside these, there is no other way to acces a component on a gameobject.

    Logic would dictate that in the Awake or Start method, all the elements would be cached (as the scripting manual suggest). Is this how it should be done ?

    As generic example, imagine a list of cities in the world, arranged in a scroll list (like the ones on iOS), and when you tap on one element, the details about that city are displayed in a panel, via strings (capital, population, language spoken, surface and so on).

    Is there a way that is equally performing to caching in advance, but that allow you the flexibility of a Find()?
     
  2. grimofdoom

    grimofdoom

    Joined:
    Sep 6, 2013
    Posts:
    168
    If said list is not excessively large, you can "cache" it by placing it inside a List<Text> for easy and direct access as the GameObjects are instantiated. I am not a professional at programming, but I use a List<GameObject> as a form of "cache" to reference GameObjects directly in my (in-progress) app for creating emblems (Like Call Of Duty, as a poor reference). From what I understand and see, it is much better performance than GameObject.Find(), though there may (and probably is) much better ways of caching references to Text than List<Text>.
     
  3. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944
    I see; so caching is the most used and most performant way to deal with components.

    Although, why a list? do you refer them as textlist [X] in your code, instead of using a name that is more descriptive? I can see issues in having a big list with no names related to it, if you have many fields to take care of.
     
  4. grimofdoom

    grimofdoom

    Joined:
    Sep 6, 2013
    Posts:
    168
    With a little hamper on the performance, you can use a foreach loop to go through the loop to find a reference. You have already shrunk your field of search majorly by it being JUST a List<> the specific object. It is not much downwards on the list unless you have more than 75 references, which I see would be very rare. The example you provided, list of cities and their population and such, would more specifically probably use an API Get to grab the information from an online database(much less performance requirements).
     
  5. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944
    I can't say without looking at numbers; but you are using a loop to add items to a list, and a loop to search the list to find your reference, when you want to update a field. To me it feels like twice as much time, compared to use for example a dictionary (from what I remember from school, a dictionary should be faster than a list in searching operations).

    I wonder how the guys that did "Cities Skyline" were able to make a game that is so UI intensive, due to the many elements, and still have decent performances.
     
  6. grimofdoom

    grimofdoom

    Joined:
    Sep 6, 2013
    Posts:
    168
    I can see how dictionaries are much faster, for somethings. But, depending on what is needed, and how it is being used, will determine which form to use. In my cases, due to math heavy, it is much faster to use lists because the location is produced before the list is used. but if you were storing and accessing data that is more specific to names or exact reference, such as a database of users or , much rare, database of cities/locations.
     
  7. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944
    Obviously each case has to be evaluated and there is no solution that fits all.

    Usually when I design, I do a comparison to see which solution has the smaller O notation; so I get a scalable solution that adapt even if my data increase. Can't beat a solution that give you O(log n), or even O(n log n); altough I steer clear from any solution that goes in the n or n^x realm, unless it is for small datasets (like less than 50 elements).

    Dictionary, by definition, has a speed of an order of magnitude better than lists; since the algorithm used for dictionary is highly optimized. But for small datasets; you may use anything, and not see much of a difference in performance :)
     
  8. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    There are dozens of other ways to access components and game objects. You can drag and drop in the inspector, keep a reference when you Instantiate it, use a static reference, use a singleton manager, use FindObjectsOfType, pass the reference in on creation, grab a reference from physics tests... The list goes on and on, I've barely started to scratch the surface.

    Once you have a proper definition of what you want to do, then we can discuss the best way to do it. Trying to optimise before you have a clear use is putting the cart before the horse.
     
  9. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944
    To be specific, I am talking of a hierarchy of elements, and how to access them.

    A canvas with 3 buttons and 3 fields is a good example; you can't call GetComponent(), since there are 3 different instances of the same component, so you can't choose which one will be returned to you (AFAIK, GetComponent does not take a name but only a type).
    You mention a dozen of ways, I have heard mostly of these:

    - drag and drop in the editor
    - GameObject.Find()
    - Transform.Find()

    A reference when you instantiate is a good way for content that you add at runtime; it may not always be the case though. Static reference still assume that you find the component first, or you create it at runtime, I believe.

    A singleton manager doesn't fall in the same category as before? You have to cache it eitehr by finding the component first, or by using a static reference when you create the component.

    FindObjectsOfType is confusing to me: the manual says that it return the first instance of object type, but the return type is an array of objects. Plus it is slow, so I never considered it better than regular gameobject.Find().

    Anyway, to boil down to the point; I can use a mix of the various techniques available, although I was looking for the fastest; which at this point seems to be either the static reference, if I create the object, or transform.Find(); which you mentioned in another post, that it is searching only on the children of a transform, and since I always have the panels reference because I create them, I can use that easily and with one single loop, reducing the time complexity of the function.

    I agree that I may be running ahead of the cart; as someone said: "premature optimization are the root of all evil"; I just don't want to end up with the app running and discover that it takes a lot of time to find children components, and have to change big chuncks of the code :) It will happen anyway, since it always happen, but I still try to be naive.

    Very educational, thanks for the reply.
     
  10. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    NO lol no no no. that is not the way you do it!!, You have clearly no idea how you do this correctly., first you make a reference of what your going to access on the stack by using the GetComponent(when you allocate). FindObjectsOfType Is slow and causes overhead. You implement a pool manager with Toolbox pattern design, so you dont need to do any Find metod, its a really a bad way of accessing. Find should be removed from Unity It has no useful application in a real game. Failure nr2. is that you want to use the inspector to link public objects. If you reload the scence you can lose this link or when instancing. I hope you dont scratch to much.. Now Boredmoron here is probably going to say i have no idea what i am talking about (. Just open opp the profiler, if you see allot of overheads, then simple dont listen to Boredmoron. I be happy to show code example how do tho this with zero overhead and 100% performance.
     
  11. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Having many elements on the gameObject? No problem, reference them 1 by 1 on awake state (and make sure script order is correct )

    ElementType = this.transform.GetChild(1).GetComponent<YourType>();
    ElementType2 = this.transform.GetChild(2).GetComponent<YourType>();
    ElementType3 = this.transform.GetChild(3).GetComponent<YourType>();

    I promise you this is the fastest way..

    Dont use FindObjectsOfType pretend you never heard it. (you are correct it does return an array)
     
    Last edited: Mar 6, 2016
    rapidrunner likes this.
  12. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,077
    Yes, that's the way I do it. I store references during Start() or Awake(), or during some initialization function of my own. What I try to do is avoid calling any of the Find or Get types of functions except when a scene loads, so it's all just done one time in the beginning. The overhead in that case doesn't typically matter because you're just doing it once, so in that case I wouldn't fuss too much about how fast the various functions are relative to each other. The overhead usually only matters if you're calling that stuff every frame which you shouldn't be doing anyway.

    FindObjectsOfType() is useful and I use it pretty often when I want to grab everything of a certain type in a scene even if the objects are inactive. The trouble with GetComponent() is that it only returns active objects. GetComponentsInChildren (plural version) can get inactive objects too by calling GetComponentsInChildren(true). Just learned that the other day, wish I knew about it a year ago. So I'll probably use that instead of Resources.FindObjectsOfType() from here on out.

    You just don't want to do this stuff every time a key is pressed or during Update() and so on. Cache it and forget it.
     
  13. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,077
    Oh, and I recommend listening to BoredMormon. He's one of the sharpest guys around here.
     
  14. Noxzo

    Noxzo

    Joined:
    Feb 16, 2014
    Posts:
    14
    Define sharp? If you follow his Principe to find objects by type (FindObjectsOfType()) then that is far from sharp.. Its a bad design practice.

    If performance is not important, then you can listen to BoredMormon or even use GameObject.Find. But seeing his general attitude/understanding on optimizing within this forum i am not really impressed with his quality contribution. Not to mention his trolling on every one he doesn't like.

    GetComponent() is fine as long as you don't cast it in loops or every frame You can cache it by simply allocating it on the stack at Awake(). FindObjectsOfType() is allot worse because it returns an array, arrays can cause overheads if the collection is huge. GetComponent() only access the elements on that object. What Ironmax here explained with GetChild() is faster and causes no overhead. Because its only doing a single index check.
     
    Last edited: Mar 8, 2016
  15. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    Where in his statement did he promote using FindObjectsOfType? All he wrote was that there are many other ways to find references than the ways already discussed.

    I usually try to grab references to objects during edit time if at all possible. Basically any object in the scene that needs a reference to another object in the scene should find this reference during edit time, that way you don't ever have to look during runtime or startup. If you're loading things in in the background not having unnecessary Start/Awake calls can make the loading smoother.
    Then again, if you have a lot of dynamically spawned objects that needs you can't really use editor time references. You can however pass them from whatever spawns the objects.

    You can use the builtin MonoBehaviour message Reset to assign references in the editor easily. Various editor scripts can be extremely powerful and are easy to create.

    So in my opinion, if you need to optimize reference performance, assign them in editor and pass them along where not possible.
     
    rapidrunner likes this.
  16. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I'm flattered. Thanks :oops:

    Almost all of the methods provided by Unity have a time and a place. FindObjectsOfType can be useful, but I agree it should be used sparingly. It's often better to simply build up a list of the components as they are created. In any case, it's not the best solution for the OP.
     
    rapidrunner likes this.
  17. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    His axe is sharp too.
     
  18. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    I think you give a better general advice than him, being more sharp and direct on the subject. Just because you list all the feature in Unity doesn't mean you give out advice . I can copy past all the features from Unity documentation on every single post where ppl need help, but it wouldn't help any one.. Better not to post at all if you ask me..


    The topic was "Most performing way to access elements"not to list all the features in Unity you "can" use..
     
    Last edited: Mar 9, 2016
  19. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Its a real axe ? :p
     
  20. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    The one in my avatar pic is made of foam. It won't kill anyone.

    I have used another one for chopping wood on occasion, not so much since I got to Australia. Fire wood is not as big a thing here.
     
  21. MV10

    MV10

    Joined:
    Nov 6, 2015
    Posts:
    1,889
    He was responding to the OP's comment: "beside these, there is no other way to acces a component on a gameobject" and so his response was entirely appropriate. It's called "reading comprehension," give it a shot.
     
    Todd-Wasson and Kiwasi like this.
  22. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944

    Agree; the more I learn how Unity does things, the easier it is to get an idea of where to place everything. I find it confusing at times; since I write mostly code for applications, so this new way of doing things is challenging at times.

    As now, I compromise with editor showing public scripts with public fields, on certain objects; so I can use drag and drop to get the reference. When not possible; I create a prefab, and then assign references on Awake().
    The main workload thou, is coming when I create objects on the fly, while the game runs; in that case I try to minimize where possible the overhead, but I end up anyway doing a transform.search, which should not hurt much (so far, stats while running the app show no big bottleneck, but I am still in a pre-alpha stage, so I did not implement many of the features yet).

    As long as a game object has only one component, I am fine using GetComponent; but I totally avoid to use the "plural" version; since it takes more time to parse through the output list of components. As usual, there is no single solution that works all the time in every situation...it is a juggling labor of love :)

    I steer away from update() altogether....I have a coroutine that manage things; so I do not have to use Update() beside in very limited case; and even there, I won't be doing anything like retrieving a component or gameobject for sure ;)
     
  23. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944
    I do listen to anyone that takes time from their life, to actually post on my threads to help me.

    I understand that we all use Unity but we may come from different "domain of expertise", so that's a unique way to see various options to solve a problem :)
     
    Ironmax likes this.
  24. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944

    Beside opinions on other members; I try to stay out of such things.

    I find personally, the transform.Find() as most "natural" way to do things; not sure how different it is, looking under the hood, compared to transform.GetChild(); so can't say anything on that.

    Personally I am trying to avoid to loop too many times through data structures; ideally I need a way to access in one shot an element, and possibly, by name. This is an old mentality that I have acquired after working so long with Visual languages.

    I am open to change, obviously, if something is obviously showing to be advantageous and its time complexity is reasonably low.


    I believe he was dissecting the problem that I raised, when I mentioned that I only know few ways to access an object.

    That was part of the conversation, true, but not the main point. I should stay more on the topic, and avoid to add non-useful info that steer from the main point (although it is hard to contain yourself when the discussion is interesting).

    You all gave me good advice, because I can see what you use and how; which is immensely helpful when learning something so vast like Unity.
     
  25. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Getchild(index) is allot faster than transform.find(string). Gl
     
  26. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944

    Although you have to do a conversion on the index....if you have 40 elements in that list, do you access each of them by writing down each index? That would cause some issues when debugging IMO.

    Imagine you want the "submit" button; you write down on a piece of paper that the button is index 20; and then while debugging you just curse in ancient Greek :)

    Otherwise you have to create a relation between the index and the name; which is another operation repeated N times (where N are the elements). Is there a way to get the child with a string, or does it accept only the index?
     
  27. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    the index is a accurate link to the hierarchy position, it doesn't loop like transform.find(string) does. That's is why its faster.

    Most of the time you can just reference it by using public and drag it in the inspector (make sure to use [System.Serializable].
    But if you just drag that script over a new object, does references are gone. (or if it reset by some strange things).

    Aware that if you change the SetSiblingIndex some way, GetChild will have different index. But since you usually do this at start, the link will be solid by code.

    Yes GetChild only returning int (SiblingIndex ) else transform.find("object name"): that is slower.
     
    Last edited: Mar 11, 2016
  28. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Another thing you can use, (that is not mention here ) is to use this.transform.FindGameObjectWithTag . If you only have 1 tag of a special item, this can be fast. Else i would avoid using that to,. Getchild is the fastest way.
     
    rapidrunner likes this.
  29. rapidrunner

    rapidrunner

    Joined:
    Jun 11, 2008
    Posts:
    944
    Using tags is not an option for me; I have a ton of objects that share a tag, so the help coming from filtering them by tag is negligible in the end.

    Will give a try and see if I can get some numbers to compare what works best in my case