2
\$\begingroup\$

I am currently trying to implement an (sort-of) Entity-Component-System. I've got the gist of it, that is, how an ECS is supposed to work. So far i have 4 classes in my design (not yet fully implemented): EntityWorld is a global container for systems, entities and their respective components. It is responsible for updating systems/stepping. EntitySystem represents the base class for a system, with a virtual update-function. Entity is a container, basically with a list of components and an id, nothing more. EntityComponent represents a component. Now, i thought about making it possible to multithread my systems, but i think i've ran into a problem here. Suppose my EntityWorld stores its entities in the simplest way possible, in a std::vector<Entity*> for example. Now, that list would either be fully passed to a system when it is updated, or the EntityWorld loops through this list and sends the entities to the systems one-by-one. In my understanding though, when using multiple threads, this would require me to lock the whole list every time a system is being updated. That would practically equal zero increase in performance, since the other threads are always waiting for the list to get free. Is there a better way to implement this? So multiple threads can be updated (and r/w to entites at the same time)? Thanks in advance!

\$\endgroup\$
7
\$\begingroup\$

The simple version: don't.

One could argue that you have perhaps a slight misunderstandings about how to build an ECS (why would you sent a list of Entity* to a system to update? the System is supposed to have its own self-contained collection of the components it cares about, and the global entity list should barely ever even be used... a "true" ECS doesn't even have an Entity object!).

Even if you fixed that, though, Systems in an ECS sense aren't the conceptual blocks that you want to thread. That leads right back into the old-school mentality of putting physics on one thread and graphics on another, which scales poorly and schedules worse (what happens when you have more cores than Systems? what happens when you have more Systems than cores?).

One alternative simple approach that is the fork-join model of parallelism. e.g., your PhysicsSystem::Update spawns a bunch of jobs for your worker threads and then waits for all those jobs to complete. No other System updates in parallel to each other; you're sequentially updating Systems but allowing those updates to go as wide as possible.

A more complex approach would be to build a full task system. Doing this very well, however, turns out to be at strong odds with an ECS approach. The problem is that ECS still relies on shared data (e.g., multiple Systems using the exact same TransformComponent) rather than having their own copies of the data.

Which is one of the many many reasons that I tell people to not use ECS. It's an over-complicated, over-constrained form of component-based design. I'll explain an alternative; bare with me, it's topical to the question. :)

Your components should be little more than glue to your low-level modules. e.g. your PhysicsComponent just contains a pointer/id that references the Box2D/Havok/PhysX body and its sole purpose is to help provide a mapping between EntityID and the physics body object. Then the physics module has its own internal data structure for physics that neither knows nor cares about your entity system.

You're forced to do this with third-party middleware, but you should build your own modules the same way. Your graphics engine should not have even the slightest clue what an entity or a component is. It should have its own internal data structures for rendering. Those data structures could have entries that correspond to entities or even entries that have nothing to do with entities. Your ModelComponent just glues your Entity to one (or more!) of the nodes in that internal structure.

Now you can freely thread your modules, as they have zero dependencies upon each other. There's some synchronization points where you copy the transform data out of physics, feed it into graphics and game logic, and then feed inputs from game logic back into physics, but that synchronization is potentially just a memcpy (but probably a loop of some kind). The entity architecture plays no part in threading, or really anything performance-sensitive at all.

\$\endgroup\$
  • \$\begingroup\$ thanks for this very thorough explanation :) i know that a true ECS doesn't have an Entity class, i just have it for convenience. EntityWorld probably isn't needed either, but its sort of a glue class, thats also used to transmit messages between systems. \$\endgroup\$ – tubberd Mar 3 '16 at 2:29
  • \$\begingroup\$ Something like an entity "world" is a great idea, as you really really want to have the concept of independent spaces/worlds in your engine. These are independent collections of game objects that do not interact in any way, and are associated with their own independent physics universes, graphics scenes, AI maps, etc. Spending a bunch of time on a pointless ECS and then zero time on incredibly useful "spaces" support is one of the most common mistakes I see. \$\endgroup\$ – Sean Middleditch Mar 3 '16 at 16:03
  • \$\begingroup\$ well, i'm still kind of inexperienced in data-oriented-design. All my "games" (some of which simple 3d games) used a classic hierarchical oop system, that worked fine enough back then. I heard good things about DOD/ECS in terms of scalability though, so i decided i would do the switch. \$\endgroup\$ – tubberd Mar 3 '16 at 16:23
  • \$\begingroup\$ do you, by any chance, have a good ECS implementation (your own or whatever) at hand that i can take a look at? \$\endgroup\$ – tubberd Mar 3 '16 at 16:25
  • \$\begingroup\$ Could you please clarify a bit further what you mean by a "module" and what kind of modules you may want to build, maybe with a couple of examples? I'm not sure I fully understand the architecture you're proposing. \$\endgroup\$ – ashes999 Jun 17 '17 at 15:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.