Godot 4.2.1
I just started working on a horde shooter, and I want as many zombies in a scene as I can feasibly have. However, any more than ~25 zombies kills my performance due to the amount of math having to be done. This is why Im considering multithreading.
-
would it be possible to get the code ran in the navigation agent node to run on the same thread as created in the script attached to the parent object?
-
would any issues arise from making a function in a thread loop indefinitely?
-
what happens when the parent that created the thread gets freed from the queue?
-
if a thread gets created every time a zombie spawns, does that cause the game to be less stable as more and more spawn?
-
how does creating lots of threads affect cpu usage outside of the game?
-
is it possible to access a pre-existing thread?
-
is it possible for all the instantiated zombies to run off the same thread?
1 Like
I’m very suspicious the navagent is not the cause of the performance issue as getting <~2 calls per frame is shocking and not close to my experience to date.
Have you confirmed this is the cause in the profiler?
2 Likes
Whenever I make the zombies get their new pathpoint really slowly, like each stagger happening once every second, the game runs fine again. I will double check, though, in case it is something else. Actually, spacing each stagger by a frame might be a good idea as well.
Upon further testing, you were correct. It is absolutely not the navigation system causing the performance issues. Thank you for having me double check that.
1 Like
Upon even further testing, the culprit for my performance issues seems to be the zombies’ movement code, as whenever I comment that out the game runs way better.
nonetheless, i want to see if i can get zombies to spawn in the hundreds, and would still appreciate it if anyone could answer any of my questions about multithreading.
I’ll caveat the following as my experience using threading has more often than not been a pita for anything more than background loading. It just seems to work better in other languages idk why.
-
I think by default it is, all code on attached to all nodes in a given scene run on the same thread unless specified otherwise. Thread groups were added in 4.x but I’ve not tinkered with them and don’t think they change default behaviour.
-
Aside from the risk of soft locking/infinite loops if poorly coded, no. In fact I would go sofar as to say this is the best way to create threads as an invite while loop that is effectively sleeping and woken with semaphores when required. This does mean you can very easily end up thrashing CPU if not using semaphores correctly or causing infinite loops as is always a risk with while loops.
-
Honestly not sure, the docs definitely mention to clean up your threads before freeing nodes, so I stick to that.
-
Stability I would’ve thought would be fine in the strictest sense unless your zombies access some shared memory (which is generally problematic but compounds as instances of this increase). But there is a cost for at creation time for a new thread that is likely to cause some stutter.
-
Using a single thread Godot is incapable of using 100% of your CPU as it is limited to a single core (not strictly true as CPU scheduler will move the thread about but the effect is the same). Using threads you could max it out and cause other apps to become unresponsive as Godot runs. It’s generally a good idea to never exceed core count-2 threads when multi threading a heavy process to give some buffer. Even if the operating system should handle it. Believe the OS class can tell you core count.
-
Absolutely, I would go further and say you should front load a thread pool as a singleton and access threads as and when you need them.
-
See above, by default they likely already do. If anything character code is hard to multi thread as it often needs access to APIs that are not thread safe like the Physics back end requiring mutexes that inevitably slow it back down.
Closing: Threading is intrinsically harder to implement and debug and can in many implementations end up being less performant than you would expect. Issues can appear to be entirely transient at times as errors can occur silently, out if order, soft lock your whole machine etc. etc.
I would generally avoid it until you’ve ruled out all other obvious performance bottlenecks and have finalised your single thread behaviour.
But also like I said at the start my experience with it in Godot is largely negative, so YMMV.
1 Like
thank you very much for the explanation, this was very nice and thorough. i will be sure to take multithreading with a grain of salt and be extra careful and be absolutely sure I know how to use them before implementing them into the game.