Many to One write relationship

I feel pretty dumb having to ask about this, it feels like it should be a straightforward thing to figure out, but I’ve been searching for this and been founding nothing so far, so here we go.

Basically, I just want Entities with an EnergyStorageComponent, and multiple other Entities that can draw energy from a given EnergyStorage Entity. In a one-to-many relationship (one EnergyStorage for many EnergyDrain)

My approach was to create EnergyDrainComponent for those entities that hold the Entity that it drains energy from and the energyDrainAmount.

However, I can’t figure how to Write a System that will sum all the energyDrainAmount from all these entities, and then decrease the EnergyStorage value by that amount, in a smart ECS way.

I’d recommend something like Approaches D or E described here. This thread uses damage as an example (consuming health), which is conceptually very similar to your use case (consuming energy)

Approach D: a parallel job writes “consume energy” events to a NativeStream, and then a single-thread job processes these events one by one. You could also write these “consume energy” events to DynamicBuffers or NativeLists or NativeQueues instead of NativeStream, but NativeStream is the most efficient of the bunch

Approach E: a parallel job directly consumes energy using “Interlocked.Add()”. In your case, you can skip the whole “writing events to a NativeStream” that we do in the example

Another simpler (and potentially better in some cases) approach is to simply do the whole thing in a non-parallel job. Keep in mind you don’t need all of your jobs to be ScheduleParallel jobs in order to exploit parallelism. In most games, if you have a single-threaded job doing some work, there’ll probably be plenty of other jobs that can be executed on other threads at the same time. Actually, 12 single-threaded jobs executing at the same time will probably be more efficient than 12 parallel jobs executing one after the other.

There’s a significant performance penalty when using ScheduleParallel jobs as opposed to single-thread. I’ve seen cases where a job that takes 3.2ms on 1 thread will take 1.1ms on 24 threads when using ScheduleParallel(). In terms of total time used across all threads, the parallel version takes 26.4ms while the singlethread version takes only 3.2ms. That’s a whole 23ms that could’ve been used by other singlethreaded jobs instead. I think Unity did mention they were working on improving parallel jobs performance though

3 Likes

Just to add to this, it really depends on whether you care about latency of throughput. Usually games are more concerned about latency, which means doing things in parallel can be better even if it is far more inefficient. Single-threaded is always going to be fastest for this problem. Approach E gets very close in parallel if your Energy is an integer type. I did come up with a 95% parallel approach for floating point numbers about a month ago which I used for an AABB combining algorithm. It relies on chunk components and allocating UnsafeLists on the fly in parallel, so it isn’t for the faint of heart. But if that’s your use case, I would be happy to share the details. :slight_smile:

1 Like