- Home /
Performance of FindGameObjectsWithTag vs Lists?
I have a segment of code that must run during each frame, goes through a selection of objects with certain tags and checks them against another object.
I've read that GameObject.Find is more performance intensive than GameObject.FindGameObjectsWithTag, so I used the latter, but since I need to run this each frame, I don't know if the performance on that is even good enough.
Since the amount of objects to check is undetermined (some scenes may have more than others), I need a dynamic list, but I need to store at least two values from the object, so I was thinking of using a struct, cache them values there during Start(), and then ForEach() during Update()
public struct someGroup
{
public int someInt { get; private set; }
public string someString { get; private set; }
public someGroup(int i, string s) : this()
{
this.someInt = i;
this.someString = s;
}
}
IList<someGroup> someList = new List<someGroup>();
someList.ForEach(something) {
// Do this one
}
foreach(something) {
// Or maybe do this one instead
}
Is the performance between the two negligible or one better than the other. I believe List.ForEach takes a slight hit over foreach too. Which of these is recommended to use?
Answer by Jamora · Jul 24, 2013 at 02:56 PM
It's all explained http://diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx. His findings state that a normal for loop is the fastest, then list.ForEach, then foreach. The difference was still rather negligible.
I think the best way for you to squeeze performance out of this, is by keeping your someList as small as possible, and not use any expensive math operations. Keep the use of GameObject.FindObjectsWithTag minimal; at zero at all if possible... never every frame.
Interesting read. I'll use a normal for loop then for me traversing. The list shouldn't be too large. In my $$anonymous$$d, I don't imagine my scenes including more than say ~10 of the particular objects I'm wanting to actually track. I'd only be using a relational and assignment operators on them.
Answer by gardian06 · Jul 24, 2013 at 03:27 PM
you can always do your own tests to see what is the most optimized for your given situation
as it pertains to your question directly Find is a slow word. basically what the system does whenever you use the word Find is it goes out through its registry of GameObjects, and tests each one then returns candidates that match the given case. the only real difference between Find(string name), and FindGameObjectsWithTag(string tag) is that the tag is expected to be in tag registry so it becomes FindGameObjectsWithTag(enum tag) just using the string version instead of the int value to compare, so the reason that FindGameObjectsWithTag is faster is that each GameObject is tested based on enum == enum instead of string == string, so if you think about it is that really that much faster considering the first actions of collect all GameObjects/test all GameObjects is still being done.
In short do not do Findx in Update unless you absolutely must.
It doesn't seem that much of a difference to be honest. It seems more natural is some cases to use Find, while in others, it seems better to use the tag. In my case, I think finding the tag seems more appropriate. Neither I want to use in Update though. Thanks for the explanation.
To add some clarification on something things I did; I did create a for loop ins$$anonymous$$d, used .Count to get the length. Looking at the whole picture, I don't know how much time I saved using a for loop with cached values in a struct opposed to using a .Find() call. But I did use .Find within the Update to get the current position of the player. I didn't know a way around that.
either by caching the player's transform/position early if(player == null){ player = GameObject.FindXXXXX();
, or by just assigning it in the inspector. Find should only ever be done in Update if there is absolutely no alternative, and the secret is "there is always an alternative to Find() in Update()"
and the overhead of FindXXX is never seen on simple tests (1-10 objects) it is always seen starting around 20+ objects and that is the killer. I think I will perform a test in a little.
So you're passing the entire object of the player to another variable. You know, I had thought about that, but never did it. I just didn't think Find was that big of a hit in my instance. I guess it could be. I can change that as well.
But for all intents and purposes, I did not use Find but twice. Once to find the current position of the player since it was always changing, and the other was to find any non specific object based on certain conditions. Both will be used only if a player has an item equipped, and even that, its conditional.
For the latter, I guess I can store more specific things within in the struct that I have. Right now it has name, distance, and position. But I didn't think through all the properties I would need to store. I could remove name, and use audioclip, since I only use name for finding the object. And I wouldn't need to find it, if I already the property I need stored in the struct.
I'd have to store an entire audio clip in a generic list of structs. That too would save computation time, just increase the amount of memory needed. (assu$$anonymous$$g many large audio clips were stored).
In a small project it really isn't a big deal if you use GameObject.Find. Once you start to have gameobjects in the thousands in a scene, you might want to not call GameObject at all, as GameObject.Find has to, in the worst case check each GO in the scene.