That's what's kind of worrying me. Right now I've mostly got a really basic rendering system, and barely any game logic. At its barebones, all this is doing is iterating entities once and updating their position. Then it's iterating their "views" and rendering them.
I've profiled the code, and it was spending most of its time in the rendering routines, so I cached sprites and that got me from 20 to 30 fps for 1000 units. Sprites are also animated, which means the animations need to be updated as well.
I think one of the ways I'm going to optimise these systems is by having them not work as a polling system, but more of a reactive system. Systems update with
run(self, dt), where dt is the time since last frame.I'm iterating everything and making all entities also execute dt, which is the simpler way to do this. For many tasks, like switching to the next animation frame, you know exactly when the entity needs to be handled next. I'm guessing switching things over to a priority queue, and popping off items as long as they need to be activated now, might make me have work only when needed. Not sure whether maintaining the priority queue is going to be more expensive than just running through all entities.
I don't really understand the problem with threading though. I imagine just having worker threads and using callbacks. If I need to handle 1000 units, split it into 4x250 and push 4 callbacks. The threads then go in and take care of it. I can probably also work on defining a process/system dependency graph and have multiple systems/processes running at once.
In general though, 1000 things on screen at once is totally enough for a ton of games. I'm also compromising some performance for the sake of nicely organised and easily extended code/gameplay. I would say that for most gamedev, especially amateur gamedev like most of us seem to be doing, using Python and pySFML is way more than enough