I'm thinking of for example making the jump action of a character, that takes ~1s, a distinct runnable, so then other threads can read its state, with additional control over the action itself by the "action thread". Are people doing this? What is there to consider when thinking about creating and destroying hundreds (or thousends) of threads a second in a bigger game or other application?
This is flawed. Some reasons here
The goals in game development:
- Keep development costs down.
- Developing with threads is more costly, it requires more developer hours. Indies can't afford it and big companies only use it when there is a proven benefit.
- Do not complicate maintenance more than needs be.
- Debugging and even sometimes reading code that uses threads, can be more complicated. For instance bugs can occur only when two specific threads do certain things which is very hard to reproduce and trace. Sometimes you may think your code does something but because it works simultaneously with multiple threads that may run in a variety of orders, it may do something else completely.
Keep the product performant.
- According to all the tests / benchmarks I and many other have done, running many threads on pc hurts performance. If you do use threads, you need to plan and use a number that is similar to the number of threads the intended architecture supports performantly (test).
- Threads require context switching, they don't actually run in parallel and you (mostly) don't control when and how long they run. If you have many threads this would result in poor performance if the "wrong" thread gets too much cpu time.
There are more good reasons:
You want to keep the focus on game design when you are developing a game. Threads are specifically used in game programming for two purposes:
- Running the same "sub-process" multiple times inside the same program (like a game server that updates players).
- Improving performance by splitting up sequential segments (intensive data computation) in your code and making them concurrent.
That 1s portion (jump code) you speak about isn't sequential in the first place. It is something that's supposed to happen in chunks between renderings to the game view.
You don't need a thread to create a
Jump object and have it listen to the game clock.
You aren't really gaining much with multithreading such a simple algorithm, it won't run faster, you won't have fewer variables, and now you have to make sure to keep everything synchronized.
You could just as easily keep track of your characters jump velocity in a regular variable and in the update loop do what you would have done in the separate thread.
The general architecture for a game looks like this:
You have a main update loop. This loop runs once per frame. The loop consists of three or four different parts (depending on whether your game really needs all of them):
- You have some logic that renders graphics onto the screen, depending on the game's current state.
- You have some logic that updates the game's physics and logic.
- Part of the loop listens for user input and updates the player-controlled elements' states accordingly.
- And part of the loop gives artificial intelligence routines an opportunity to provide input for computer-controlled elements.
Notably, all four of these components run on the same thread. Game programming typically is the task of filling in the details for these components (no small task, of course) and keeping each piece performant enough that the entire loop can run dozens of times a second.
So, instead of creating a thread specifically to take care of a character's jump, you would provide logic for how the character's jump affects the character's physics in the character's logic. Then, in the physics/logic component of the loop, you would use this logic to update the character's state one frame at a time. In many cases, this would specifically be that when a character receives a jump input from the user or AI, you give the character a sudden upwards velocity on the next frame, then let the physics engine handle what happens on subsequent frames.
Again, at no point does this particular architecture require additional threads.
To answer your question more directly, you can't even afford to create and delete 100s and 1000s of threads per second.
In some languages there are constructs often referred to as "green threads" where a single thread doesn't map to an OS managed thread, but JVMs aren't based on those (in general, anymore). Creating OS managed threads is extremely expensive. Most machines with cave in at thousands of threads being created just for benchmark purposes.
Once you factor in the fact that you're actually using the threads, and that you're not creating these threads once, but rather creating them, destroying them, and creating new ones every second you'll find that most machines simply can't handle the workload. With the default settings of the JVM just creating 500 threads will use over 256mb of memory (and that's not considering what kind of havoc this will all wreak on the scheduler). That memory won't be returned instantly when you delete the threads, and within seconds you'd find the JVM starved for memory.
My point isn't that the JVM is doing something wrong by not using "green threads". The name "green thread" might imply that they're somehow better than OS managed threads, but they have their own limitations especially related to taking advantage of multiple cores (and Java has it's own constructs for dealing with the cost of thread creation). Rather my point is the approach you're considering is actually impossible from a hardware standpoint (amongst other issues).
I think you could look at using an event based system if you want to have shared states like this. Your jump can be implemented to call invoke certain events when various parts of the action occur, such as at the start of a jump, the highest point etc. That being said, as the other answers have mentioned you really should consider if you actually require that level of complexity for your game-play, or it's all solely for the sake of your code's design.